给定一个类和一个子类
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;属性)。也许我会努力解决这个问题的方法,这可能会导致另一个问题。但是现在,我可以通过阻止派生对象添加到通用列表来避免这个问题吗?
答案 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属性是导致编译器错误的原因。