在C#中,你可以将一个泛型类型转换为另一个T参数是第一个T的子类吗?

时间:2011-07-08 14:59:05

标签: c# generics casting

我遇到了一个问题,我有一个泛型,我正在尝试转换为另一个,其中第二个通用T参数是第一个中使用的子类。

这是我的代码,为了理解而简化...

public partial class HierarchicalItem
{
    public ObservableHierarchicalCollection<HierarchicalItem> ContainingCollection{ get; private set; }

    public HierarchicalItem Parent{ get{

        return (ContainingCollection != null)
            ? ContainingCollection.Owner
            : null;

    }}

}

public partial class HierarchicalItem
{

    public class ObservableHierarchicalCollection<T> : ObservableCollection<T>
    where T : HierarchicalItem
    {
        public ObservableHierarchicalCollection(HierarchicalItem owner)
        {
            this.Owner = owner;
        }

        public HierarchicalItem Owner{ get; private set; }

        private void ExistingMemberCheck(T item)
        {   
            if(item.ContainingCollection != null) throw new ExistingMemberException();
            item.ContainingCollection = this; // <-- This fails because of casting
        }

        protected override void InsertItem(int index, T item)
        {
            ExistingMemberCheck(item);
            base.InsertItem(index, item);
        }

        protected override void SetItem(int index, T item)
        {   
            CheckParent(item);

         // Get the item and unhook the hierarchy
            var existingItem = this[index];
            existingItem.ContainingCollection = null;

            base.SetItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
         // Get the item and unhook the hierarchy
            var existingItem = this[index];
            existingItem.ContainingCollection = null;

            base.RemoveItem(index);

        }

    }

}

那么我该如何解决这个问题呢?

3 个答案:

答案 0 :(得分:4)

C#4.0支持显式协方差和反方差。

您可以在 ObservableCollection 界面声明中使用 out 关键字:

public interface ObservableCollection <out T> { 

   //The ObservableCollection  methods 
}

然后界面将是共变体。

更多关于它:

Covariance and Contravariance (C# and Visual Basic)

Covariance and Contravariance FAQ

How is Generic Covariance & Contra-variance Implemented in C# 4.0?

答案 1 :(得分:0)

将顶部切换为类似的东西:

public partial class HierarchicalItem
    {
        public INotifyCollectionChanged ContainingCollection { get; private set; }

        public HierarchicalItem Parent
        {
            get
            {

                return (ContainingCollection != null)
                    ? ((ObservableHierarchicalCollection<HierarchicalItem>)ContainingCollection).Owner
                    : null;

            }
        }

    }

你必须使用非通用接口,因为正如尼古拉斯所说,在这种情况下,共同方差是你的敌人。

答案 2 :(得分:0)

在您的示例中,ObservableHierarchicalCollection<T>仅使用T = HierarchicalItem进行实例化。如果情况总是这样,您可以尝试使该集合非通用,而是继承ObservableCollection<HierarchicalItem>

如果没有,您可以将HierarchicalItem更改为抽象和通用,(HierarchicalItem<T> where T : HierarchicalItem<T>),如IComparable和类似接口。然后,您将拥有DerivedItem : HierarchicalItem<DerivedItem>,它将具有ObservableHierarchicalCollection类型的ContainingCollection。请注意,这可能会使混合项目类型变得困难。