在非泛型类中的C#协方差

问题描述:

我真的在所有的协方差问题中搜索,没有什么看起来像我的问题。在非泛型类中的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

请尝试以下操作。 这个想法是在使用时捕获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

如果这是可能的,那么也可以将原始对象重新分成非通用基础,这些基础可以直接存储在用户控件中。 –

这是尽我所知不可能的。

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

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

要使用协方差和逆变需要一个接口!

协方差:IInterface<out T>

逆变:IInterface<in T>

检查此链接了解更多信息: http://weblogs.asp.net/dixin/archive/2009/08/31/understanding-csharp-covariance-and-contravariance-3-samples.aspx

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类之外。 –