在C#中,您能否将一种泛型类型转换为另一种';st参数是第一个';那是什么?

在C#中,您能否将一种泛型类型转换为另一种';st参数是第一个';那是什么?,c#,generics,casting,C#,Generics,Casting,我遇到了一个问题,我试图将一个泛型转换为另一个泛型,其中第二个泛型T参数是第一个中使用的泛型T参数的子类 这是我的代码,为便于理解而简化 public partial class HierarchicalItem { public ObservableHierarchicalCollection<HierarchicalItem> ContainingCollection{ get; private set; } public HierarchicalItem Pa

我遇到了一个问题,我试图将一个泛型转换为另一个泛型,其中第二个泛型T参数是第一个中使用的泛型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);

        }

    }

}
公共部分类层次结构项
{
public observehierarchicalcollection包含集合{get;private set;}
公共层次结构项目父项{get{
返回(包含集合!=null)
?包含集合。所有者
:null;
}}
}
公共部分类层次结构项
{
公共类ObservableHierarchicalCollection:ObservableCollection
其中T:HierarchicalItem
{
公共ObservieHierarchicalCollection(HierarchicalItem所有者)
{
这个。所有者=所有者;
}
公共层次结构项目所有者{get;private set;}
私有无效现有成员检查(T项)
{   
如果(item.ContainingCollection!=null)抛出新的ExistingMemberException();
item.ContainingCollection=this;//C#4.0支持显式协方差和反向方差

您可以在ObservableCollection接口声明中使用out关键字:

public interface ObservableCollection <out T> { 

   //The ObservableCollection  methods 
}
公共接口ObservableCollection{
//可观测采集方法
}
然后,接口将是共变的

更多信息:


将顶部切换为类似以下内容:

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

        public HierarchicalItem Parent
        {
            get
            {

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

            }
        }

    }
公共部分类层次结构项
{
public INotifyCollectionChanged包含集合{get;private set;}
公共层次结构项父项
{
得到
{
返回(包含集合!=null)
((ObservableHierarchicalCollection)包含集合)。所有者
:null;
}
}
}

您必须使用非通用接口,因为正如Nicholas所说,协方差在这种情况下是您的敌人。

在您的示例中,
ObservateHierarchicalCollection
仅使用
T=HierarchicalItem
进行实例化。如果总是这样,您可以尝试将集合设置为非通用和inheri改为从
可观察到的采集中提取


如果没有,您可以将
HierarchicalItem
更改为抽象和通用,(
HierarchicalItem,其中T:HierarchicalItem
)就像IComparable和类似的接口一样。然后你会有
DerivedItem:HierarchicalItem
,它会有一个类型为ObserverHierarchicalCollection的包含集合。请注意,这可能会使混合项目类型变得困难。

看看@Magnus的可能重复,而不是重复。他说的是成员。我说的是abo但是集合本身。另外,我专门指的是所有可能显示这一点的泛型,仅以我的代码为例。他的重点是列表及其内容。(看,我本可以用非基于集合的类来演示这一点。)你说得对。需要声明为接口。-修复了答案。请注意,我的答案假设为3.5或更低。如果使用4.0,请使用Yochai的答案。