通用协方差问题

时间:2012-09-30 12:47:17

标签: c# generics covariance

我正在尝试研究一些包含字典及其包含的项目的通用接口,这两种接口目前看起来像下面的代码。

正如你所看到的,我对词典进行了抨击,使得价值成为对象。理想情况下,我喜欢TParentMOdel的协变量KEy和TModel的协变值的接口,就像项目一样,但到目前为止我还没有能够解决这个问题(不确定它是否可能)。

在我尝试添加下面最后一个用法示例中的最后一项之前,我的工作似乎有效。 GenderVm本质上是一个ISatteliteVm

似乎就像问题是性别是一个Enum,这对我来说并不完全合理。在这种情况下,TParentModel是Person,它是Party的子类。 Covariance似乎在这里工作,因为我可以添加TParentModel是Person的其他项目。

这就是为什么我说它似乎就像问题是性别的问题。它是一个枚举,虽然枚举是一个我认为的对象,但类型约束系统不支持枚举。

是否有一个简单的修复,例如演员表? A有没有人看到更好的方法来设计SatelliteMap?

干杯,
Berryl

项目

public interface ISatelliteVm<out TParentModel, out TModel> : ISatelliteVm
{
    TParentModel ParentModel { get; }
    TModel Model { get; }
}

词典

public class SatelliteVmMap<TParentModel> : Dictionary<Type, ISatelliteVm<TParentModel, object>>, IEditableObject, IIsDirty
{

    public void Add(ISatelliteVm<TParentModel, object> item) {
        if (item == null)
            throw new ArgumentNullException("item");
        Add(item.GetType(), item);
    }
}

用法(包含SatelliteMap的抽象类)

public interface IHubViewModel<out TModel> where TModel : Entity
{

    public void AddSatelliteVm(ISatelliteVm<TModel, object> vm) {
        if (_satelliteVmMap == null) {
            _satelliteVmMap = new SatelliteVmMap<TModel>();
        }
        if (_satelliteVmMap.ContainsKey(vm)) return;

         _satelliteVmMap.Add(vm);
    }
}

用法(包含ISatelliteVm的几个条目的子类)

    public abstract class PartyDetailVm : HubViewModel<Party>
{
    ...

    public LifespanVm LifespanVm { get { return GetSatelliteVm<LifespanVm>(); } }
    public AvatarVm AvatarVm { get { return GetSatelliteVm<AvatarVm>(); } }
    public TelecomNumberPcmShellVm TelecomNumberPcmShellVm { get { return GetSatelliteVm<TelecomNumberPcmShellVm>(); } }

    ...
}

用法(包含ISatelliteVm的几个条目的子类)

public class PersonDetailVm : PartyDetailVm
{
    ...

    public PersonNameVm PersonNameVm { get { return GetSatelliteVm<PersonNameVm>(); } }
    public HonorificVm HonorificVm { get { return GetSatelliteVm<HonorificVm>(); } }

    // THIS is the problem child I cannot add to the map
   ** public GenderVm GenderVm { get { return GetSatelliteVm<GenderVm>(); } } **

 }

ERROR

  

错误82参数1:无法从'Parties.Presentation.ViewModels.PimDetailVms.PersonDetailVms.GenderVm'转换为       'Core.Presentation.Wpf.ViewModels.MasterDetailVms.DetailVms.SatelliteVms.ISatelliteVm'

编辑比利

Billy,SatelliteVm只是一个实现ISatelliteVm的基类。 Person是Party的子类,Gender是一个枚举。

public class GenderVm : SatelliteViewModel<Person, Gender>
{
}

GenderVm的变化似乎可以解决问题(不确定原因!)

 public class GenderVm : SatelliteViewModel<Person, Gender>, ISatelliteVm<Party, object>
{

    Party ISatelliteVm<Party, object>.ParentModel { get { return base.ParentModel; } }

    object ISatelliteVm<Party, object>.Model { get { return base.Model; } }
}

1 个答案:

答案 0 :(得分:2)

请参阅documentation

  

仅针对参考类型支持通用接口的差异。值类型不支持方差。例如,IEnumerable<int>无法隐式转换为IEnumerable<object>,因为整数由值类型表示。

这必须解决您的问题。

也许您应该将Gender更改为班级?