【问题标题】:Problems with abstract types and interafaces as generic type params with the new() constraint抽象类型和接口作为具有 new() 约束的泛型类型参数的问题
【发布时间】:2010-01-06 18:34:08
【问题描述】:

我需要将泛型类型参数作为接口,但是我想在泛型类 (SomeGenericType) 中实例化该类型,如下所示:

class Program
{
    static void Main(string[] args)
    {
        var val = new SomeGenericType<ISomeInterface>();

        Console.ReadKey();
    }
}

internal class SomeGenericType<T> where T : new()
{
    public SomeGenericType()
    {
        var test = new T();  
    }
}

public class SomeClass : ISomeInterface
{
    public string TestVal { get; set; }
}

public interface ISomeInterface
{
    string TestVal { get; set; }
}

这会引发以下编译时错误:

“ISomeInterface 必须是具有公共无参数构造函数的非抽象类型,才能将其用作泛型类型或方法 SomeGenericType 中的参数 'T'”

我明白为什么会这样,但是我想知道有没有办法解决这个问题?

谢谢。

【问题讨论】:

  • 添加额外的约束有帮助吗? where T : ISomeInterface, new()。正如您所提到的,您将需要为泛型提供一个具体的实现,因为没有其他方法可以保证 new() 约束。
  • 如果你有Interface1,Class1:Interface1,Class2:Interface1,编译器应该如何猜测你是要创建Class1还是Class2的实例?

标签: c# generics constraints


【解决方案1】:

不,new() 约束要求可以使用语法创建类型的实例

new T()

这显然不适用于抽象类或接口,只有具有公共无参数构造函数的具体类。

您可以通过删除约束将问题推迟到运行时,并使用:

Activator.CreateInstance<T>()

而是创建对象。然后,只要在运行时使用的实际类型满足这些约束,您的代码就会按照您的意愿工作。但是,如果您确实尝试使用接口或抽象类,则会遇到运行时错误。

在您的具体情况下,此行会引发异常

var val = Activator.CreateInstance<SomeGenericType<ISomeInterface>>();

您已经过了编译时错误,但没有效果。

【讨论】:

    【解决方案2】:

    另一种想法,可能无关紧要,但看起来您正在寻找一种方法来请求ISomeInterface,并提供其“默认”实现SomeClass 的实例。这是控制反转 (IOC) 容器可以为您处理的事情。如果您想进一步研究,可以查看 Spring.NET、Microsoft Unity、AutoFac、LinFu 或许多其他框架之一。

    【讨论】:

      【解决方案3】:

      问题是,编译器无法知道为给定接口实例化哪个类。正如大卫 M 指出的那样:

      这是控制反转 (IOC) 容器可以为您处理的事情

      我认为对于这个简单的要求,使用框架可能会过火。您可以像这样创建自己的 Factory 类:

      public class Factory
      {
        Dictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();
      
        public void Register<IType, CType>()
        {
          typeMapping.Add(typeof(IType),typeof(CType));
        }
      
        public IType Create<IType>()
        {
          Activator.CreateInstance(typeMapping[typeof(IType)]);
        }
      }
      

      进行一些健全性检查,这个类应该可以使用了。

      【讨论】:

        【解决方案4】:

        这里的问题是new 约束与具体的类型实现有关。这不能与简单的接口或抽象类一起使用,因为它们不能直接实例化。你必须在这里提供一个具体的类

        var val = new SomeGenericType<SomeClass>()
        

        【讨论】:

          猜你喜欢
          • 2013-08-10
          • 2014-05-07
          • 1970-01-01
          • 1970-01-01
          • 2020-09-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多