【问题标题】:Workaround for new() constraint with parameters in generics具有泛型参数的 new() 约束的解决方法
【发布时间】:2014-07-22 12:04:59
【问题描述】:

我知道,这里有一些关于 SO 的答案,似乎可以解决我的问题,例如 thisthat 线程。但在我的具体情况下,有一些区别。

在我的问题前面:这是在带有参数的泛型中管理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' 必须是具有公共无参数的非抽象类型 构造函数,以便将其用作泛型类型中的参数“T”或 方法'MyGeneric'

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

!!!解决方案!!!

提供的答案诱使我进行修改,即可以删除 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; }
}

就是这样,也感谢所有 cmets!

【问题讨论】:

  • workaround to manage 是什么意思?
  • 我过去通过使用另一个泛型参数TFactory 来解决这个问题,该参数受new() 的约束,以及一个返回另一种类型T 的接口,方法签名可以在其中使用参数。但是这种方法有些局限,我不记得我使用它的场景了。
  • 关于第二个问题:因为这是签名要求的class MyGeneric&lt;T&gt; : BaseClass where T : IGenerate, new() - , new() 表示“必须是具有公共无参数构造函数的非抽象类型"
  • 你不能做new T(arg1, arg2,...)。那么你可以使用反射Activator.CreateInstance(选择相关的重载)。但有几点需要注意: 1. 反射可能会失败。 2. 反射发生在运行时,所以没有编译器优化。
  • @DanielA.White :我想知道,如果我以后在使用这些结构时会遇到问题,也许是文本中的一个不清楚的短语;)

标签: c# generics


【解决方案1】:

不是最好的解决方案,但我曾经做过的是需要一个返回泛型类型并提供构造函数作为函数参数的函数:

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

要调用方法,使用名为 Foo 的类作为泛型:GenericMethod((arg) =&gt; new Foo(arg))

args 不需要在调用泛型方法之前定义,仅用于指示 ctor 的参数将如何使用。它也使方法更加灵活,因为调用者可以选择使用方法而不是构造函数,例如 System.Drawing.Image.FromFile() 或使用返回它的 lambda 表达式的现有对象。

【讨论】:

    【解决方案2】:

    问题
    再次是我的主要问题:这是管理带有参数的泛型中的 new() 约束的可能/智能解决方法吗?

    回答
    您传递了一个类型(ClassX)并希望在不创建实例的情况下访问一个实例函数(GenerateNew) -> 这是您需要考虑的一个问题。 您可以创建一个静态工厂(和\或使用 IOC)来按类型创建新对象。

    问题
    为什么 BaseClass 和 ClassX 需要有一个无参数的构造函数,而它们在任何情况下都不会显式使用?

    回答
    此约束要求使用的泛型类型是非抽象的,并且它具有允许您调用它的默认(无参数)构造函数。 顺便说一句,您正在通过 new T() 使用空 ctor。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多