泛型集合是否可以阻止添加派生对象

时间:2014-09-18 14:37:26

标签: c# generics serialization

给定一个类和一个子类

public class Base
{
  public string Name { get; set; }
}

public class Derived : Base
{
  public string Extra {get; set; }
}

和通用列表

var list = new List<Base>();

我想阻止这个:

var b = new Base { Name = "base" };
var d = new Derived { Name = "derived", Extra = "stuff" };

list.Add(b); // this is good
list.Add(d); // this is BAD

想要阻止这种情况的原因是列表将以丢失类型信息的方式序列化,然后重新序列化为List<Base>。从[{1}}派生的任何项目都需要向下转换为反序列化程序未知的类型(我当然不希望使用反射来查找继承自Base的类并且具有&#39; Extra&#39;属性)。也许我会努力解决这个问题的方法,这可能会导致另一个问题。但是现在,我可以通过阻止派生对象添加到通用列表来避免这个问题吗?

4 个答案:

答案 0 :(得分:3)

public class UberStrongTypedList<T> : IList<T>
{
    private readonly IList<T> _list = new List<T>();

    public void Add(T item)
    {
        if (item.GetType() == typeof (T))
            _list.Add(item);
        else
            ;//some error
    }

    public void Clear()
    {
        _list.Clear();
    }

    //SNIP...
}

答案 1 :(得分:1)

为什么不进行简单的检查:

if(!obj is Derived)
{
   list.Add(obj);
}

如果您想要与基类完全比较,那么您可以这样做:

if(obj != null && obj.GetType() == typeof(Base))
{
    list.Add(obj);
}

请记住,这些检查无法阻止没有这些检查的代码,无法将子类对象添加到列表中。您的另一个选择是创建自定义List<T>课程,源自List<T>并提供new添加方法,如this answer.

中所述

答案 2 :(得分:1)

不,使用C#类型系统是不可能的。继承的整个前提是派生对象可以被视为它们是任何基类型(或接口)的实例。

您可以创建一个新集合,当项目尝试添加时,会进行运行时检查以验证该类型是否与集合泛型类型的完全匹配,但是&#39;关于你能做的最好的事情。您无法获得此约束的静态类型验证。

答案 3 :(得分:-1)

列出一个列表:

private class Parent
{
    public int ID { get; set; }
}

private class Child : Parent
{

}

private class MyList : List<Parent>
{
    public new void Add(Parent item)
    {
        //runtime type check in case a Parent-derived object reaches here
        if (item.GetType() == typeof(Parent))
            base.Add(item);
        else
            throw new ArgumentException("List only supports Parent types");
    }

    [Obsolete("You can't add Child types to this list", true)]
    public void Add(Child item)
    {
        throw new NotImplementedException();
    }
}

static void Main(string[] args)
{
    var list = new MyList();
    list.Add(new Parent() { ID = 1 });
    list.Add(new Child() { ID = 2 }); //This gives a compiler error
}

请注意,带有true参数的Obsolete属性是导致编译器错误的原因。