2013-02-06 68 views
2

我真的在所有的協方差問題中搜索,沒有什麼看起來像我的問題。在非泛型類中的C#協方差

我有一個用戶控件(這個類不能是通用的,出於顯而易見的原因),它看起來像這樣:

class MyUserControl : UserControl 
{ 
    private BaseDao<object> _dao; 
    private AppointmentMapping<object> _mapping; 

    // I need these 2 generics to type safe the mapping/dao relation 
    public void RegisterPersistence<T>(BaseDao<T> dao, AppointmentMapping<T> mapping) 
    { 
     // These two dont work. even with safe and unsafe casting. 
     _dao = dao; 
     _mapping = mapping; 
    } 
} 

我已經嘗試過存儲協方差,接口委託等它只是不要存儲對象! 我怎樣才能做到這一點?這很容易用Java實現。

+1

這個問題似乎與'UserControl'無關。它可以發生在任何類。你可以考慮編輯這個問題,使它更「通用」... –

+0

我不知道BaseDao和AppointmentMapping的定義,但如果它們確實是泛型類,泛型參數沒有共同/反對差異在C# – SWeko

+1

關鍵是你不告訴你以後如何訪問這些字段。當然,將它們存儲爲'object'將起作用。如果以後需要在另一個代碼塊中訪問這些字段,則需要再次使用'',然後您可以強制轉換爲對應於正確的實現,或將使用該字段的代碼註冊到委託中(類型爲Action) ,例如並在稍後執行。否則,使BaseDoa和AppointmentMapping實現非通用接口並將其用於字段類型。 – Sebastian

回答

2

請嘗試以下操作。 這個想法是在使用時捕獲T,並將其存儲在「知道以後要做什麼」的類中。然後通過一個接口在類中引用該項目(省略類型信息)。 稍後通過界面調用存儲值。這樣你就不需要重構泛型類來實現某些接口。

class MyUserControl : UserControl 
    { 

    // hold a reference to the helper - no generics needed here -> "covariant" 
    private IHelper helper; 

    // I need this 2 generics to type safe the relation between the mapping and the dao 
    public void RegisterPersistence<T>(BaseDao<T> dao, AppointmentMapping<T> mapping) { 
     // "pass <T>" for later usage 
     this.helper = new HelperImpl<T>(dao, mapping); 
    } 

    // use the stored values... 
    public void doStuff() { 
     helper.doStuff(); 
    } 

    // the non generic interface 
    private interface IHelper 
    { 
     void doStuff(); 
    } 

    // a generic implementation for storing the items *and* using them. 
    private sealed class HelperImpl<T> : IHelper 
    { 
     private readonly BaseDao<T> dao; 
     private readonly AppointmentMapping<T> mapping; 

     public HelperImpl(BaseDao<T> dao, AppointmentMapping<T> mapping) { 
     this.dao = dao; 
     this.mapping = mapping; 
     } 

     public void doStuff() { 
     this.dao.foo(); 
     this.mapping.foo(); 
     } 
    } 
    } 
+0

謝謝!做成它,結果是sweeeeeeeeet。 – Stew

+0

如果這是可能的,那麼也可以將原始對象重新分成非通用基礎,這些基礎可以直接存儲在用戶控件中。 –

0

這是盡我所知不可能的。

就像塞巴斯蒂安說,你可以做的是有

class MyUserControl : UserControl 
{ 
    private object _dao; 
    private object _mapping; 

    // I need this 2 generics to type safe the relation between the mapping and the dao 
    public void RegisterPersistence<T>(BaseDao<T> dao, AppointmentMapping<T> mapping) 
    { 
     _dao = dao; 
     _mapping = mapping; 
    } 


    public BaseDao<T> GetDao<T>() 
    { 
     return _dao as BaseDao<T>; 
    } 

    public AppointmentMapping<T> GetAppointmentMapping<T>() 
    { 
     return _mapping as AppointmentMapping<T>; 
    } 
} 
+0

它不會工作,因爲我將使用類中的對象。 – Stew

+0

這很難,或者像我說的,不可能。你想做什麼? –

+0

就是這樣,將DAO存儲在UserControl中,然後將用戶存儲在事件中以保存數據。 – Stew

0

H.alex是正確的,最好的辦法是移動通用有點不同的層上所以你可以使類是泛型的,然後使用泛型類成員而不是對象。這個類必須能夠推斷出泛型類型或者你必須寫類似:

public class BaseDao<T> 
{ 
    public T Item { get; set; } 
} 

public class TestClass 
{ 
    private BaseDao<object> _dao; 

    public void RegisterPersistence<T>(BaseDao<T> dao) 
    { 
     _dao = Activator.CreateInstance<BaseDao<object>>(); 
     //need to map each member of BaseDao 
     _dao.Item = dao.Item; 
    }  
} 

這顯然不是維護,你必須採取所有映射成員的新實例的照顧。

+0

這不是一個協方差,它是一個不變量,你將無法將 –

+0

轉換爲真,在這裏添加一個協變接口,該類需要包含約束(來自接口)。正如所說的最好的事情是將通用部分移到MyUserControl類之外。 –