2010-10-07 41 views
4

我有一段代碼是這樣工作的算法:籠統地說需要對不同的數據成員

void someAlgorithm(SomeType someVar) 
{ 
    someVar.someMember = createSomeValue(); 
    lock(something) 
    { 
    SomeType someOtherVar = something.Find(someVar.unrelatedMember); 
    if(someOtherVar != null) 
     someOtherVar.someMember = someVar.someMember; 
    } 
} 

(我需要去適應它一下,用於發佈,所以請我,如果我承擔這樣做把事情搞糟了。)

現在我需要的代碼,這個確切的一塊爲另一成員someVar(其中有一個相關的,但不同類型的)和另一個創建函數。我知道我可以把這些代碼,複製它,替換一些標識符,然後完成。但我覺得這樣做很骯髒。我覺得應該有一種方法來推廣這個小算法。

我知道我可以隨時通過創建函數作爲代表,但我不知道該怎麼概括成員訪問,然後有不同類型的成員(和創造功能)的問題。

在C++中,我會用成員指針與這樣的模板相結合。成員指針並不完全是小菜一碟,但是一旦我查看了他們奇怪的語法,我會在幾分鐘內完成。如何在C#中做到這一點?

編輯:因爲這似乎並不太清楚,這裏是相同的算法的其他實例是這樣的:

void someOtherAlgorithm(SomeOtherType someVar) // 1 change here 
{ 
    someVar.someOtherMember = createSomeOtherValue(); // 2 changes here 
    lock(something) 
    { 
    SomeOtherType someOtherVar = something.Find(someVar.unrelatedMember); 
    if(someOtherVar != null) 
     someOtherVar.someOtherMember = someVar.someOtherMember; // 2 changes here 
    } 
} 

我希望這闡明瞭這一點。

+0

這個方法體是完全一樣? – NullUserException 2010-10-07 16:05:17

+0

@NullUserException:是的,除了'someMember'的所有用法被'someOtherMember'和'createSomeValue()'用'createSomeOtherValue()'代替。 – sbi 2010-10-07 16:34:30

+0

'someOtherVar'與'someVar'是同一類型嗎? – SLaks 2010-10-07 16:42:49

回答

3

你弄得我有點,有。你someAlgorithm採取所謂someOtherVarSomeType類型的參數,並聲明具有相同的名稱(所以它不能作爲編譯是)一個局部變量。從你的兩個定義看來,someVarsomeOtherVar是同一類型(SomeType),但你的本地變量只能用var來聲明,所以它不是完全清楚它們是否是。

在您的評論對你意味着someVarsomeOtherVar是不同類型的(即使你的問題,你報你在談論的someVar不同成員而SLaks是問你兩個變量的部分SLaks someVarsomeOtherVar )。所以我會假設他們是不同的類型,而someOtherVar只是一個局部變量,而不是一個參數。

基於這些假設:

void someAlgorithm<TMember>(
    SomeType someVar, 
    Func<TMember> create,     // replaces "createSomeValue" 
    Func<SomeType, TMember> getter,   // replaces get for "someMember" 
    Action<SomeType, TMember> setter,  // replaces set for "someMember" 
    Action<SomeOtherType, TMember> setter2) // replaces set for "someMember" 
              // on "someOtherVar" (not necessary 
              // if "someOtherVar" is actually 
              // the same type as "someVar") 
{ 
    setter(somevar, create()); 

    lock(something) 
    { 
    SomeOtherType someOtherVar = something.Find(someVar.unrelatedMember); 

    if(someOtherVar != null) 
     setter2(someOtherVar, getter(someVar)); 
    } 
} 

對於你的第一個算法,這將被稱爲像:

someAlgorithm(
    someVar, 
    createSomeValue, 
    x => x.someMember, 
    (x, y) => { x.someMember = y; }, 
    (x, y) => { x.someMemberOfOtherType = y; } 
); 

對於你的第二個:

someAlgorithm(
    someVar, 
    createSomeOtherValue, 
    x => x.someOtherMember, 
    (x, y) => { x.someOtherMember = y; }, 
    (x, y) => { x.someOtherMemberOfOtherType = y; } 
); 
+0

對不起,我感到困惑。當我試圖提取算法時,我懷疑我搞砸了,但是,當然,我沒有看到它......無論如何,感謝您的努力(正確)推斷我需要的東西。看起來你已經找到了做我想做的事情的方法(從我那裏得到'+ 1'),儘管它和我擔心的一樣:維護複製的代碼比這更容易。 ':('那麼到目前爲止算法已經大大增加了,而且還有兩個問題是同樣的問題,所以看起來這是值得的。 – sbi 2010-10-07 17:59:49

+0

@sbi:關於這個代碼的可維護性:我同意所有因爲這個原因,我建議可能定義一些* interface *,它可以用你想要的方式處理這個算法中的不同對象,這樣就不用接受'SomeType'和4(!)了。代表,你的算法可以接受'SomeType'和一個提供4種類似方法的接口實例。 – 2010-10-07 18:31:51

1

您可以傳遞一個創建lambda表達式和設置的值。

例如:

void someAlgorithm<TObject, TProperty>(TObject someVar, Func<TProperty> creator, Action<TObject, TProperty> setter, Action<SomeType, TProperty> relatedSetter) 
{ 
    var value = creator(); 
    setter(someVar, value); 
    lock(something) 
    { 
    var someOtherVar = something.Find(someVar.SomeOtherMember); 
    if(someOtherVar != null) 
     relatedSetter(someOtherVar, value); 
    } 
} 


someAlgotihm(something, createSomeValue, (x, v) => x.someProperty = v, (x, v) => x.someProperty = v); 
+0

請再讀一遍我的問題。我已經添加了算法的第二個實例。我還需要更改'someOtherVar.someMember = someVar.someMember'這行''傳遞lambda表達式來做到這一點幾乎不可讀。此外,這是否說明了不同數據成員是不同類型的? – sbi 2010-10-07 16:40:24

+0

你可以爲'someOtherVar'傳遞另一個lambda(或者重用第一個lambda是類型和屬性是相同的)。泛型允許不同的類型。 – SLaks 2010-10-07 16:42:00

+0

在'someVar.SomeOtherMember'部分看起來'someVar.SomeOtherMember'部分在'someVar'可以是任意的'TObject'(除非添加一個強制'TObject'派生自某個基類的通用約束)時不會真正起作用。 – 2010-10-07 17:11:51

3

我認爲最好的辦法是使用Func代表,並通過一個簡單的選擇器功能作爲參數的算法。您可以使該方法一般,使得選擇可以返回任何類型的成員:

void someAlgorithm<T>(SomeType someVar, SomeType someOtherVar, 
         Func<SomeType, T> selector) { 
    someVar.someMember = createSomeValue(); 
    lock(something) { 
    var someOtherVar = something.Find(selector(someVar)); // Use 'selector' 
    if(someOtherVar != null) 
     someOtherVar.someMember = someVar.someMember; 
    } 
} 

然後,你可以寫類似:

someAlgorithm(some1, some2, a => a.SomeOtherMember); 

沒有你的實際代碼的詳細信息,這是一個有點難以精確地寫出答案(例如,如果您正在比較值,您可能需要對泛型類型參數進行一些限制 - 例如IComparable),但這通常是解決問題的最佳方法。

如果您需要在設置代碼中的另一個參數/獲取的someMember值,則只會增加其他功能。例如Action<SomeType, T>(爲其設置值)以及另一個成員的另一個「選擇器」功能。在通話中,這將是(s, val) => s.SomeMember = val。如果someMember具有不同的類型,那麼您可能需要再添加一個類型參數。

+1

我建議你再添加一個例子,如何以通用的方式將作業賦予someMember。 – 2010-10-07 16:13:24

+0

請再次閱讀我的問題:而不是'someMember'我需要'someOtherMember'。你的這個沒有幫助。該算法幾乎完全如我的問題所示。 – sbi 2010-10-07 16:38:18

相關問題