【问题标题】:Using a type to instantiate a derived class which uses restricted generics使用类型实例化使用受限泛型的派生类
【发布时间】:2018-04-13 04:44:55
【问题描述】:

我正在使用通用工厂类,其中通用部分是正在使用的派生类。正常用法很清楚: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) {...}
}

【问题讨论】:

  • 你为什么不让 MyMainClass 也通用呢?所以你可以通过 Generic Type 参数?而且您将拥有内部字段类型安全而不是“对象”。
  • @fildor 老实说,到目前为止我还没有想到那种方式(“mymainclass”在我的程序中是 Web 服务的业务逻辑,并没有考虑到使那个通用的,但老实说,我喜欢这个主意。)
  • 不清楚您在寻找什么。请详细说明或分享一些伪代码以显示您的要求。
  • 我认为你被设计模式缠住了,以至于忘记了保持简单。请尝试澄清问题,不清楚您在问什么。
  • @Reza 我不确定你的意思。我问我如何才能最好地实例化这些类,以便我可以使用 Exists 和/或 ExistsB(并且还可以自动完成来显示它们)

标签: c# generics


【解决方案1】:

你可以创建一个你传递的任何类型的实例:

_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("...");

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

【讨论】:

    【解决方案2】:

    这是你想要的吗?

    Object instance1 = Activator.CreateInstance<Object>();
    Object instance2 = Activator.CreateInstance(typeof(object));
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        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:最好将依赖传递到类生命周期的上层,而不是在内部激活它,因此您可以使用工厂为您创建它们,甚至是依赖注入。 p>

        PS2:在抽象类之前使用接口。 Interfaces/Constructors/Methods 描述了您的整体依赖关系。另一方面,抽象类只是一种重用实现的方式——它们并不意味着定义接口或您如何使用类,您可以将整个主体设为私有/受保护而无需共享任何内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-03
          • 2011-04-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多