使用类型来实例化使用受限泛型的派生类

时间:2018-04-04 08:27:57

标签: c# generics

我使用通用工厂类,其中通用部分是正在使用的派生类。正常用法很明确:BaseClass<DerivedA> C = new BaseClass<DerivedA>().现在虽然我试图将属性注入到我使用这些类的类中。为此,我尝试将Type作为参数(以便我可以注入正在使用的派生类)。

尽管我有点不知所措,尽管我正在寻找自己的例子并试图自己。我现在想知道:这样的构造是否可以使用?如果是这样,我如何实例化该类并使用Exists和ExistsB?

用法:

public class MyMainClass
{
    object _ClassInstance; // BaseClass<DerivedA> or BaseClass<DerivedB>

    public MyyMainClass(Type typeIWant)
    {
          .....
    }
}

....
MyMainClass a = new MyMainClass(typeof(DerivedA));
MyMainClass b = new MyMainClass(typeof(DerivedB));

通用类:

public abstract class BaseClass<T> where T: BaseClass<T>, new()
{
...
    public bool Exists(int a) {...}
}

派生类:

public class DerivedA :BaseClass<DerivedA>
{
...
}

public class DerivedB :BaseClass<DerivedB>
{
...
   public bool ExistsB(string a) {...}
}

4 个答案:

答案 0 :(得分:4)

您可以使用以下方法创建任何类型的实例:

_ClassInstance = Activator.CreateInstance(typeIWant)

不建议使用,因为当您想要使用其中一种BaseClass方法时,您将永远检查其类型并进行转换。如果您能够更改主类以获取类型参数,它应如下所示:

public class MyMainClass<T> where T: BaseClass<T>, new()
{
    T _ClassInstance; // BaseClass<DerivedA> or BaseClass<DerivedB>

    public MyMainClass()
    {
        _ClassInstance = new T();
    }
}

这将允许您使用BaseClass上定义的任何方法。如果你想使用ExistsB,那么你仍然需要在运行时检查它的类型并进行转换。我会推荐这样的东西:

if (_ClassInstance is DerivedB derivedB)
    derivedB.ExistsB("...");

如果你真的需要编译时检查,我会推荐它,你的课程需要改变。您不能仅使用对基类的引用来访问派生类上定义的方法或属性。

答案 1 :(得分:1)

这是你想要的吗?

import itertools

答案 2 :(得分:0)

我建议您使用getType来获取类型名称。如果您升级继承(从DerivedB等继承另一个类),如果使用getType,您可以确保仅为DerivedB类型的实例调用此方法。

MyMainClass b = new MyMainClass(typeof(DerivedB));

if(b.GetType() == typeof(DerivedB)) 
b.ExistsB(...);

答案 3 :(得分:0)

这是抽象类的主要问题 - 您共享接口和实现。但在您的情况下,您强烈依赖于不同的接口。为了简化问题,只需看看你真正想要的东西:

public interface IExistable<in TValue>
{
    bool Exists(TValue value);
}

public interface IDerivedA : IExistable<int>
{
}

public interface IDerivedB : IExistable<int>, IExistable<string>
{
}

正如您所看到的,您使用两个接口过度复杂IDerivedB,即您的MainClass在某些情况下依赖于IDerivedB。扩展接口也不错,你只是错误地使用它。所以你必须做的是定义MainClass的接口:

public interface IMainClass
{
    //some methods here
}

创建两个实现:

public class ConcreteMainClass : CommonMainClass //you can derive from common, delegate to inner instance or implement interface from scratch - you decide depending on situation
{
    private readonly IDerivedB _instance;
    public ConcreteMainClass(IDerivedB instance) : base(instance)
    {
        _instance = instance;
    }

    //you can override some logic here depending on IExistable<string> from IDerivedB
}

public class CommonMainClass : IMainClass
{
    private readonly IExistable<int> _instance;
    public CommonMainClass(IExistable<int> instance)
    {
        _instance = instance;
    }

    //this is where you don't depend on IExistable<string>
}

通过这种方式,您可以编写更清晰的代码:

IMainClass a = new CommonMainClass(new DerivedA());
IMainClass b = new ConcreteMainClass(new DerivedB());

PS :最好将依赖项传递给类生命周期的上一级,而不是在内部激活它,这样你就可以使用工厂为你创建它们甚至是依赖注入。

PS2 :在抽象类之前使用接口。接口/构造函数/方法描述了您的整体依赖关系。另一方面,抽象类只是重用实现的一种方式 - 它们不是用来定义接口或者你如何使用类,你可以使整个主体私有/受保护而不会分享任何东西。