簡體   English   中英

泛型中帶有參數的 new() 約束的解決方法

[英]Workaround for new() constraint with parameters in generics

我知道,這里有一些關於 SO 的答案,它們似乎解決了我的問題,比如這個那個線程。 但在我的具體情況下,有一些區別。

在前面我的問題:這是一種可能/智能的解決方法來管理帶有參數的泛型中的new()約束嗎?

假設有以下基類:

abstract class BaseClass
{
    internal BaseClass()
    {
        Console.WriteLine("{0}'s ctor (parameterless)", "BaseClass");
    }

    internal BaseClass(object parent)
    {
        Console.WriteLine("{0}'s ctor", "BaseClass");
        Parent = parent;
    }

    public object Parent { get; private set; }
}

和界面:

interface IGenerate
{
    IGenerate GenerateNew(int x, object parent);
}

基類僅用於存儲父對象,接口提供了一個方法來返回調用其構造函數的實現類的對象,如下所示:

class ClassX : BaseClass, IGenerate
{
    public ClassX()
    {
        Console.WriteLine("{0}'s ctor (parameterless)", "ClassX");
    }

    public ClassX(int x, object parent)
        : base(parent)
    {
        Console.WriteLine("{0}'s ctor", "ClassX");
        X = x;
    }

    public IGenerate GenerateNew(int x, object parent)
    {
        Console.WriteLine("{0}.GenerateNew()", "ClassX");
        return new ClassX(x, parent);
    }

    public int X { get; private set; }
}

我的泛型類旨在生成和存儲調用接口方法的提供類的對象:

class MyGeneric<T> : BaseClass where T : IGenerate, new()
{
    public MyGeneric(int x, object parent)
        : base(parent)
    {
        Console.WriteLine("{0}'s ctor", "MyGeneric");
        Instance = new T().GenerateNew(x, this);
    }

    public IGenerate Instance { get; private set; }
}

另一個類繼承了泛型:

class ClassXSpecifier : MyGeneric<ClassX>
{
    public ClassXSpecifier(int x, object parent)
        : base(x, parent)
    {
        Console.WriteLine("{0}'s ctor", "ClassXSpecifier");
    }
}

這些結構的使用是這樣的:

var classXspecifier = new ClassXSpecifier(5, null);
var classX = (ClassX)classXspecifier.Instance;
Console.WriteLine(classX.X);

輸出:

BaseClass's ctor
MyGeneric's ctor
BaseClass's ctor (parameterless)
ClassX's ctor (parameterless)
ClassX.GenerateNew()
BaseClass's ctor
ClassX's ctor
ClassXSpecifier's ctor
5

再次我的主要問題:這是一種可能/智能的解決方法來管理帶有參數的泛型中的new()約束嗎?

第二個問題:為什么BaseClassClassX需要有一個無參數構造函數,而它們在任何情況下都不會顯式使用 如果我刪除它們,我會收到以下錯誤:

“ClassX”必須是具有公共無參數構造函數的非抽象類型,以便將其用作泛型類型或方法“MyGeneric”中的參數“T”

提前致謝,克里斯蒂安 =)

!!! 解決方案 !!!

提供的答案誘使我進行修改,即可以刪除new()約束 -> 因此也可以刪除無參數構造函數。

我刪除了接口,並在BaseClass添加了一個靜態方法來生成新對象:

public static BaseClass GenerateNew(Type T, object[] args)
{
    return (BaseClass)Activator.CreateInstance(T, args);
}

所以泛型類可以減少到

class MyGeneric<T> : BaseClass
{
    public MyGeneric(int x, object parent)
        : base(parent)
    {
        Console.WriteLine("{0}'s ctor", "MyGeneric");
        Instance = GenerateNew(typeof(T), new[] { x, parent });
    }

    public BaseClass Instance { get; private set; }
}

就是這樣,也感謝所有評論!


再次我的主要問題:這是一種可能/智能的解決方法來管理帶有參數的泛型中的 new() 約束嗎?

回答
您傳遞了一個類型(ClassX)並希望在不創建實例的情況下訪問一個實例函數(GenerateNew)-> 好吧,這是您需要考慮的一個問題。 您可以創建一個靜態工廠(和/或使用 IOC)來按類型創建新對象。


為什么 BaseClass 和 ClassX 需要有一個無參數構造函數,而它們在任何情況下都不會顯式使用?

回答
此約束要求使用的泛型類型是非抽象的,並且它具有允許您調用它的默認(無參數)構造函數。 順便說一句,您正在通過執行new T()來使用空 ctor。

不是最好的解決方案,但我曾經做過的是需要一個返回泛型類型並提供構造函數作為函數參數的函數:

void GenericMethod<T>(Func<string, T> ctor)
{
    T t = ctor("foo");
}

要調用該方法,請使用名為 Foo 的類作為泛型類型: GenericMethod((arg) => new Foo(arg))

args 不需要在調用泛型方法之前定義,僅用於指示如何使用 ctor 的參數。它還使方法更加靈活,因為調用者可以選擇使用方法而不是構造函數,像 System.Drawing.Image.FromFile() 或使用返回它的 lambda 表達式的現有對象。

暫無
暫無

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

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