【问题标题】:Instantiating a generic field of a class实例化类的通用字段
【发布时间】:2016-05-06 18:20:36
【问题描述】:

有没有办法让类中的泛型字段专门用于构造函数中的特定类型?

例如:

class concreteClass1
{
    private int a;
    public concreteClass1( int a)
    {
        this.a = a;
    }
}

class concreteClass2
{
    string b;
    public concreteClass2(string b)
    {
        this.b = b;
    }
}

class A<T>
{
    private T field;
    public A(int x)
    {
        field = new concreteClass1(x); //error here CS0029
    }

    public A(string y)
    {
        field = new concreteClass2(y); //error here CS0029
    }
}

所以T 可以是concreteClass1concreteClass1,它们各自的ctors 会有不同的签名。

【问题讨论】:

  • 有人写信时你想做什么:new A&lt;concereteClass2&gt;(42);?
  • 这似乎是XY Problem。你想做什么需要你这样做?
  • 通用代码应该是通用的。泛型代码的全部意义在于,无论使用什么特定类型,它都可以工作。事实上,你的代码没有,事实上只有在使用一种类型时才有效,这意味着它实际上不是泛型的,所以你不应该使用泛型。
  • @kuhaku 这听起来像ElectricFuel 应该有一个共同的接口或基类。不确定您在做什么,这甚至要求它不仅仅是一个简单的枚举。
  • @kuhaku 那你的 oo 一般是有缺陷的。

标签: c# .net generics constructor field


【解决方案1】:

我会重构它以使用依赖注入。这样,该类不包含创建它所依赖的其他类的代码,例如myConcreteField = new ConcreteA&lt;T&gt;(4);。依赖注入用于防止代码像这样陷入困境。

(您的示例非常非常抽象,这使得它有点困难。如果您使用“具体”和“实施”之类的类名,那么它会使答案更难阅读,因为我们使用相同的词来描述概念。 )

相反,无论Concrete 是什么,声明一个接口,比如

public interface ISomethingThatTheOtherClassNeeds<T>
{
    public int MySomething {get;set;}
}

public class SomethingThatTheOtherClassNeeds : ISomethingThatTheOtherClassNeeds<string>
{
    public int MySomething {get;set;}
}

然后在你的Implementation 类中:

class Implementation<T>
{
    private readonly ISomethingThatTheOtherClassNeeds<T> _something;

    public Implementation(ISomethingThatTheOtherClassNeeds<T> something)
    {
        _something = something;
    }

    void DoSomething()
    {
        Console.Write(_something.MySomething.ToString());
    }
}

不同之处在于,它不是负责创建该类是什么,而是在构造函数中传递给ImplementationImplementation 甚至不知道类是什么——它只知道它与接口匹配。

如果这些其他类又依赖于更多类,这将特别有用。如果您通过在班级中调用new 来创建它们,那么该班级必须知道如何创建这些班级。

然后将其连接起来,您可以使用 Windsor、Unity、Autofac 等依赖注入容器。这在控制台应用程序中并不常见,但我猜这更像是实验性的而不是真实的。

【讨论】:

    【解决方案2】:

    由于必须转换类型,这有点棘手。也许这对你有用?

    class Program
    {
        static void Main(string[] args)
        {
            var myImplementation = new Implementation<int>(4);
            var myImplementation2 = new Implementation<string>("Hello World");
    
            Console.WriteLine(myImplementation.myConcreteField); // outputs 4!
            Console.WriteLine(myImplementation2.myConcreteField); // outputs Hello World
        }
    }
    
    abstract class MyAbstract<T>
    {
        public T MySomething;
        public MyAbstract(T something)
        {
            MySomething = something;
        }
    }
    
    class ConcreteA<T> : MyAbstract<T>
    {
        public ConcreteA(int something) : base((T)Convert.ChangeType(something, typeof(T)))
        {
        }
    }
    
    class ConcreteB<T> : MyAbstract<T>
    {
        public ConcreteB(string something) : base((T)Convert.ChangeType(something, typeof(T)))
        {
        }
    }
    
    class Implementation<T>
    {
        public MyAbstract<T> myConcreteField;
    
        public Implementation(T a)
        {
            myConcreteField = new ConcreteA<T>(4);
        }
    
        void DoSomething()
        {
            Console.Write(myConcreteField.MySomething.ToString());
        }
    }
    

    【讨论】:

    • 这比使用object 代替泛型类型参数有什么好处?如果您不将该类用作泛型类...不要使其泛型。
    • @Luaan myConcreteField 已经转换为正确的类型。除此之外,我认为没有理由。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-26
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 2020-07-25
    相关资源
    最近更新 更多