簡體   English   中英

通用集合可以阻止添加派生對象嗎

[英]Can a generic collection prevent the adding of derived objects

給定一個類和一個子類

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> Base派生的任何項都需要向下轉換為反序列化器未知的類型(我當然不希望使用反射來查找從Base繼承並具有'Extra'屬性的類)。 也許我會努力解決這個問題,這可能會引發另一個問題。 但是現在,我可以通過阻止將派生對象添加到通用列表中來避免此問題嗎?

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...
}

為什么不簡單檢查一下:

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

如果要與基類進行精確比較,則可以執行以下操作:

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

請記住,如果沒有這些檢查這些檢查就無法阻止將子類對象添加到列表中的代碼。 您的另一種選擇是創建自定義List<T>類,從派生List<T>並提供一個new Add方法在解釋這個答案。

不,使用C#類型系統是不可能的。 繼承的整個前提是可以將派生對象視為它們的任何基本類型(或接口)的實例。

您可以創建一個新集合,當嘗試添加一個項目時,將進行運行時檢查以驗證該類型是否與該集合的泛型類型完全匹配,但這是您能做到的最好的選擇。 您將無法獲得此約束的靜態類型驗證。

子類化一個列表:

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屬性是導致編譯器錯誤的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM