2010-11-14 144 views
2
使用C#泛型

(語言是C#在VS 2008)爲了避免代碼重複

我有以下問題: 有許多結構(作爲來自第三方)的所有實施某些具有相同簽名的方法。 我想用包裝類來包裝這些結構體,這些包裝類實現了一個特定的接口,以便可以統一處理這些類。 實施例:

interface AnInterface 
{ 
    void DoSomething(); 
} 

struct Struct1 
{ 
    public void DoSomething(); 
} 

class Struct1Wrapper : AnInterface 
{ 
    private Struct1 m_struct; 
    public override void DoSomething() // AnInterface implementation 
    { 
     m_struct.DoSomething(); 
    } 
} 

注意Struct1 DoSomething方法是混凝土而Struct1Wrapper通過更容易處理的接口實現它。

這同樣與Struct2等等 - StructXWrapper的代碼是除了Struct1通過StructX

更換同我已經爲了避免代碼重複使用泛型嘗試:

class GenericStructWrapper<AStruct> : AnInterface 
{ 
    private AStruct m_struct; 

    public override void DoSomething() // AnInterface implementation 
    { 
     m_struct.DoSomething(); 
    } 
} 

但這是行不通的,因爲編譯器沒有關於AStruct DoSomething()方法的概念。

任何其他的想法如何實現這一點,而無需複製Struct1Wrapper的代碼? 也許有一些類似宏觀的特徵或者反射的一些用法?

謝謝,

Ury Jamshy。

+0

當你引用一個VALUETYPE作爲一個接口,您應該知道, valueType將每次被裝箱。 – 2010-11-14 17:10:33

回答

6

您可以在接受該方法的類構造函數中使用Action<AStruct>

然後,您可以創建實例像new GenericStructWrapper<Struct1>(s => s.DoSomething())

3

C#不安全支持結構類型(除了在某些特殊環境),所以沒有辦法讓這個完全安全沒有代碼重複。您必須採用SLak的技術,要求客戶端提供代表(可能會涉及重複相同的lambda表達式)或假設基礎類型將滿足包含public void DoSomething()方法的合同。

與第二個選項去,這裏是在C#中使用dynamic 4的一種方法:現在

public class StructWrapper: AnInterface 
{ 
    private readonly dynamic m_struct; 

    public StructWrapper(object myStruct) 
    { 
     m_struct = myStruct; 
    } 

    public void DoSomething() 
    { 
     m_struct.DoSomething(); 
    } 
} 

,你可以儘量使這個類通用的,與底層的結構類型爲通用型的參數,但這可能不會幫助你所有那麼多,除非你對想要對包裝類型執行結構特定的操作。下面是其一個例子,具有反射和代表(C#3兼容):

public class StructWrapper<T> : AnInterface where T : struct 
{ 
    private readonly Action action; 

    // deliberately exposed 
    public T UnderlyingStruct { get; private set; } 

    public StructWrapper(T underlyingStruct) 
    { 
     UnderlyingStruct = underlyingStruct; 
     action = (Action)Delegate.CreateDelegate 
        (typeof(Action), underlyingStruct, "DoSomething"); 
    } 

    public void DoSomething() 
    { 
     action(); 
    } 
} 

請注意,可以混合和匹配兩種技術上面提到的,例如反射但沒有泛型。

用法:

AnInterface wrapper1 = new StructWrapper(new Struct1()); 
wrapper1.DoSomething(); 

StructWrapper<Struct1> wrapper2 = new StructWrapper<Struct1>(new Struct1()); 
wrapper2.DoSomething(); 
Struct1 s = wrapper2.UnderlyingStruct; // generics help here 
s.SomeOtherMethod(); 
+0

請注意,在VS 2008中,'dynamic'尚未可用。你需要VS2010或安裝.NET 4.0,並直接從命令行編譯該代碼(通過C#編譯器'csc.exe')。 – stakx 2010-11-14 15:51:55

+0

@stakx:我提供了一個與C#3兼容的替代方案,因此可以與VS2008一起使用。 – Ani 2010-11-14 15:54:04

0

有這個語法:

class GenericStructWrapper<AStruct> : AnInterface where AStruct : AnInterface 
{ 
    private AStruct m_struct; 

    public override void DoSomething() // AnInterface implementation 
    { 
     m_struct.DoSomething(); 
    } 
} 

這是說AStruct必須實現AnInterface

+3

AStruct表示的類型沒有實現AnInterface - 我們不能改變它,因爲這些是來自第三方庫的結構,如問題所述。 – 2010-11-14 15:44:52