为什么构造函数中不允许使用类型参数?

时间:2012-05-11 07:46:53

标签: c#

方法有类型参数。为什么构造函数没有类型参数?

实施例

我认为有几个(不是很多)例子会有用。我目前的问题是:

internal class ClassA
{
   private readonly Delegate _delegate;

   public ClassA<T>(Func<T> func)
   {
     _delegate = func;
   }
}

Delegate对我的班级来说已经足够了。但要将其作为方法组传递,我需要将参数定义为Func<T>

5 个答案:

答案 0 :(得分:2)

他们根本没有包含该功能,可能假设它不会非常有用。

如果构造函数需要它,则可能需要整个类型。但是在你不这样做的情况下,你可以使用Object。

如果你不能......是的,我不认为有很多方法,对不起。 :\你可以使用反射,但当然这是非常慢的...或者你可以动态生成方法的技巧,这可能是值得的,这取决于你的用例,但也可能很慢(它至少增加1额外的间接呼叫)。

答案 1 :(得分:2)

因为构造函数是类的一部分,所以类型参数可能属于整个类型。

如果在构造泛型类的实例时可以选择使用不同的类型参数,那么实际上构建的是不同类型的类。我知道它与C ++中的模板化类不同,但概念类似。

要解决您的特定问题,您可以使用“模板化”工厂方法。

答案 2 :(得分:2)

在阅读C#规范之后,它确实有意义,但它可能会令人困惑。

每个类都有一个关联的实例类型,对于泛型类声明,实例类型是通过从类型声明创建构造类型形成的,每个类都是提供的类型参数是相应的类型参数。

class C<T>
{ 
}

C<T>是一个构造类型,实例类型将由使用类型参数构造类型的过程创建。

C<String> c = new C<String>();

编译器采用构造类型C<T>,并使用提供的类型参数创建了C<String>的实例类型。泛型只是一个编译时构造,所有内容都是在运行时以闭合构造类型的形式执行的。

现在让我们回答您的问题并在此进行测试。

class C
{
    public C<T>() 
    {
    }
}

这是不可能的,因为您正在尝试构建一个不存在的类型。

C c = new C<String>();

implicitexplicit之间的CC<String>转化是什么?空无一人。它甚至没有意义。

因为在此示例中C是非泛型类型,所以实例类型是类声明本身。那么您希望C<String>如何构建C

你要做的正确声明就是这个。

internal class Class<T> 
{
    private readonly Delegate _delegate;

    public Class(Func<T> function) 
    {
        _delegate = function;
    }
}

这里因为我们有一个构造类型Class<T>,所以编译器可以创建正确的实例类型。

Func<String> function = new Func<String>(() => { return String.Empty; });
Class<String> c = new Class<String>(function);

如果您尝试按照自己想要的方式进行操作。

Func<String> function = new Func<String>(() => { return String.Empty; });
Class c = new Class<String>(function);

构造的类型为Class<String>,与类型C不同,并且任何一个都没有implicitexplicit转换。如果编译器允许这样做,C将处于某种未知且不可用的状态。

您需要了解的构造类型是什么。

class C<T>
{
    public C<T>() 
    {
    }
}

虽然您无法显式声明泛型构造函数,但它在运行时仅作为闭合类型构造函数有效。

C<String> c = new C<String>();

在编译时,将创建以下构造函数。

public C<String>() 
{
}

这就是为什么这是有效的:

C<String> c = new C<String>(); // We just used the closed type constructor

如果你想要的东西被允许,可能会发生这样的事情。

class C<T>
{
    public C<U>() 
    {
    }
}

// ???
C<String> c = new C<Int32>();

如果允许构造,您可以看到现在出现的问题。希望这有一些见解,规范相当长,并且许多部分涵盖了泛型,类型参数,构造类型,封闭和开放类型,绑定和未绑定。

它可能会变得非常混乱,但编译器规则不允许这是一件好事。

答案 3 :(得分:1)

您可以传入委托而不是强类型的Func&lt; T&gt;。您将无法在编译时知道类型,但是当您传入Func&lt; T&gt;时,您将不会知道该类型。无论是。如果你想要,你必须使整个类通用。

class Program {
        static void Main(string[] args) {
            Func<int> i = () => 10;
            var a1 = new ClassA(i);

            Func<string> s = () => "Hi there";
            var a2 = new ClassA(s);            
        }
    }

    internal class ClassA {
        private readonly Delegate _delegate;

        public ClassA(Delegate func) { // just pass in a delegate instead of Func<T>
            _delegate = func;
        }
    }

答案 4 :(得分:0)

因为您可以通过将您的类声明为通用

来实现这一目标
internal class ClassA<T>
{
 private readonly Delegate _delegate;

  public ClassA(Func<T> func)
  {
    _delegate = func;
  }
}
那么你将隐含一个遗传构建