【问题标题】:In C#, can you cast one generic type to another who's T parameter is a subclass of the first's T?在 C# 中,您可以将一个泛型类型强制转换为另一个 T 参数是第一个 T 的子类的类型吗?
【发布时间】:2011-07-08 14:59:04
【问题描述】:

我遇到了一个问题,我尝试将一个泛型转换为另一个泛型,其中第二个泛型 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);

        }

    }

}

那么我该如何解决呢?

【问题讨论】:

  • @Magnus,不是重复的。他说的是会员。我说的是收藏本身。另外,我专门指的是所有可能显示这一点的泛型,仅以我的代码为例。他专注于列表及其内容。 (IOW,我可以用非基于集合的类来证明这一点。)

标签: c# generics casting


【解决方案1】:

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?

【讨论】:

  • 你是对的。需要声明为接口。 - 修正了答案。
【解决方案2】:

将顶部切换为这样的:

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

        public HierarchicalItem Parent
        {
            get
            {

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

            }
        }

    }

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

【讨论】:

  • 请注意,我的答案假定为 3.5 或以下。如果使用 4.0,请使用 Yochai 的答案。
【解决方案3】:

在您的示例中,ObservableHierarchicalCollection&lt;T&gt; 仅使用T = HierarchicalItem 实例化。如果情况总是如此,您可以尝试将集合设为非泛型并改为从 ObservableCollection&lt;HierarchicalItem&gt; 继承。

如果没有,您可以将HierarchicalItem 更改为抽象和通用的,(HierarchicalItem&lt;T&gt; where T : HierarchicalItem&lt;T&gt;) 就像 IComparable 和类似接口一样。然后你会得到DerivedItem : HierarchicalItem&lt;DerivedItem&gt;,它会有一个 ObservableHierarchicalCollection 类型的 ContainingCollection。请注意,这可能会使混合项目类型变得困难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2021-02-08
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多