簡體   English   中英

泛型類型,其類型參數是抽象基類

[英]Generic type whose type parameter is an abstract base class

假設我有一個名為Animal基類和兩個名為LionTiger 派生類 我還想有一個名為AnimalList<Animal>通用類型來包含Animal成員。 例如:

var list = new AnimalList<Animal>();

list.Add(new Lion());
list.Add(new Tiger());

到目前為止非常簡單,但是有一個問題……我希望基類Animalabstract 也就是說, 我不想允許創建基類的實例。 但是,使基類抽象化不會令人驚訝地導致錯誤CS0310 (請參見下面的完整示例)。

我確實提出了一個解決方案:根據需要使基類成為非抽象類,並僅從默認(無參數)構造函數中引發異常:

public Animal()
{
    throw new System.NotImplementedException();
}

但這使我感到有些不安。 有沒有更好的辦法?


這是一個完整的示例,說明了我上面描述的方案:

// public class Animal {}        // OK
public abstract class Animal {}  // 'abstract' keyword causes error 'CS0310'

public class Lion : Animal {}
public class Tiger : Animal {}

public class AnimalList<T> :
    Animal
    where T : Animal, new()
{
    public void Add(T animal) {}
}

class AnimalListDemo
{
    static public void Main(string[] args)
    {
        // The following statement causes:
        // error CS0310 - 'Animal' must be a non-abstract type with a
        // public parameterless constructor in order to use it as
        // parameter 'T' in the generic type or method 'AnimalList<T>'

        var list = new AnimalList<Animal>();

        list.Add(new Lion());
        list.Add(new Tiger());
    }
}

只需刪除new()約束即可。 它要求您提供一個可以通過new()實例化的類(這是所有要求的全部內容),但是抽象類顯然不能做到這一點。

MSDN

新約束指定通用類聲明中的任何類型參數都必須具有公共的無參數構造函數。 要使用新的約束,類型不能為abstract

在泛型參數上絕對必須具有new()約束嗎? 如果刪除它,它將編譯,但代價是不允許在AnimalList創建T新實例。

這樣做的原因是,如果您要求該類具有一個公共的,無參數的構造函數,則它不能是抽象的,因為抽象類是專門為不可創建的,但是您要求使用new()創建該類。 。 由於這些要求彼此矛盾,因此編譯器會抱怨。

該解決方案似乎是一種破解,並且也不起作用,因為派生類構造函數還將調用基類構造函數(而不是完全覆蓋它),並且仍會引發異常。

在問題的最后,我問:

有沒有更好的辦法?

從本頁的有用答案得出的結論是的!

特別是,@ CodesInChaos在對我的問題發表評論時說:

通常,我會認為new()約束有點代碼味道。

這讓我在尋找new()約束的替代方法。 (我確實確實需要在我的類層次結構內的基類中創建泛型類型參數的實例。)

我在以下答案中找到了要尋找的東西: 創建沒有新約束的T的新實例

var instanceOfT = new T(); // Before

var instanceOfT = (T)Activator.CreateInstance(typeof(T)); // After

這使我可以刪除源代碼中的一些new()約束。 最后,刪除new()約束使我可以根據需要將中間類設置為abstract

接口可以與new約束結合使用:

public interface IAnimal {}

public abstract class Animal : IAnimal {} 

public class AnimalList<T> where T : IAnimal, new() {}

但是,您的第一行仍將失敗:

var list = new AnimalList<Animal>();

AnimalList<Animal> (或AnimalList<IAnimal> )不是有效類型,因為無法構造給定的T 你確定新的是你想要什么?

暫無
暫無

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

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