简体   繁体   English

C#工厂的通用继承

[英]C# Factory for generic inheritance

I apologize for this rather fundamental question, however, I could find no documentation. 对于这个基本问题,我深表歉意,但是我找不到任何文档。 Perhaps because I do not know the proper terminology. 也许是因为我不知道正确的术语。

Class structure: 类结构:

class D{}

abstract class A<T>{}
class B<T> : A<T> {}
class C : B<D> {}

I attempt to create a factory method returning C, while the overall return type must be A. Unfortunately this implementation will produce a compiletime error, altough the inheritance structure seems to be consummately covariant. 我尝试创建一个返回C的工厂方法,而总返回类型必须为A。不幸的是,此实现将产生一个编译时错误,尽管继承结构似乎是协变的。

public A<T> FactoryMethod()
{
   return new C();
}

More specifically, I am trying to implement a factory, able to produce all three classes based on a input value, while the generic capability has to be obtained. 更具体地说,我试图建立一个工厂,该工厂能够根据输入值生成所有三个类,而必须获得通用功能。

public A<T> FactoryMethod(int i, Type K)
{
   if(i == 1)
      return new A<K>():

   if(i == 2)
      return new B<K>():

   if(i == 3)
      return new C():
}

Update 更新

I have to create three objects as follows. 我必须创建三个对象,如下所示。

A<string> first = FactoryMethod(1, string);
A<int> second = FactoryMethod(2, int);
A<int> third = FactoryMethod(3, int);

In the scope of the class containing FactoryMethod , T is meaningless. 在包含FactoryMethod的类的范围内, T是没有意义的。 You need to specify the generic parameter of A in order to use it as a type. 您需要指定A的通用参数才能将其用作类型。

In this case, because C is B<D> , and B<D> is A<D> , then you would use A<D> as the return type. 在这种情况下,由于CB<D> ,而B<D>A<D> ,那么您将使用A<D>作为返回类型。

For your second question, if you make the factory method generic I think you can get what you want. 对于第二个问题,如果使工厂方法通用,我想您可以得到想要的。

public class A<T> {}

public class B<T> : A<T> {}

public class C : B<D> {}

public class D {}

public class Test
{
    public static A<T> FactoryMethod<T>(int i)
    {
       if(i == 1)
          return new A<T>();
       if(i == 2)
          return new B<T>();
       if(i == 3)
          return (A<T>)(object)new C();
       return null;
    }

    public static void Main()
    {
        A<string> first = FactoryMethod<string>(1);
        A<int> second = FactoryMethod<int>(2);
        A<D> third = FactoryMethod<D>(3);
    }
}

Because C ( A<D> ) isn't assignable to some A<T> (the compiler doesn't know that you'll always pass 3 when T is D ) this isn't type-safe. 因为CA<D> )不可分配给某些A<T> (编译器不知道当TD时总是会传递3 ),所以这不是类型安全的。

C is a sub class of the bound type A<D> . C是绑定类型A<D>的子类。 So the following is valid: 因此,以下内容是有效的:

public A<D> FactoryMethod()
{
   return new C();
}

since we can safely say that C is a A<D> . 因为我们可以肯定地说CA<D> However C is not a generic type and cannot be converted to the open type A<T> where T is a generic argument since T could be any type. 但是C不是通用类型,并且不能转换为开放类型A<T> ,其中T是通用参数,因为T可以是任何类型。

However the following is valid: 但是,以下内容有效:

public A<T> FactoryMethod()
{
   return new B<T>();
}

Since B<T> is an open generic type as well and any B<T> is an A<T> . 由于B<T>也是开放的泛型类型,并且任何B<T>都是A<T>


Based on your update, you could write your factory method as: 根据您的更新,您可以将工厂方法编写为:

public A<T> FactoryMethod<T>(int i)
{
   if(i == 1)
      return new A<T>():
   if(i == 2)
      return new B<T>():
   if(i == 3) 
      return (A<T>)(object)new C():
      // The cast to object gets rid of compile time checking,
      // but will throw an InvalidCastExceptoin if T is not D
}

This is a bit ugly with that weird hack for case 3. Then you would call it as: 对于案例3来说,这个怪异的骇客有点丑陋。然后您将其称为:

A<string> first = FactoryMethod<string>(1);
A<int> second = FactoryMethod<int>(2);
A<int> third = FactoryMethod<int>(3); // InvalidCastException!

Given this: 鉴于这种:

class D{}

class A<T>{}
class B<T> : A<T> {}
class C : B<D> {}
enum openT
{
    level1, level2
}

I think that you might be looking for this: 我认为您可能正在寻找:

public A<T> FactoryMethod<T>(openT i)
{
   if(i == openT.level1)
      return new A<T>():

   if(i == openT.level2)
      return new B<T>():

}

public A<D> FactoryMethod()
{
    return new C():
}

public static void Main()
{
    A<string> first = OpenFactoryMethod<string>(1);
    A<int> second = OpenFactoryMethod<int>(2);
    A<D> third = FactoryMethod();
}

Note that A cannot be abstract since you are trying to construct it. 请注意,A不能抽象,因为您正在尝试构造它。

I'm failing to see what you are really trying to accomplish here though, since C is a closed type, and therefore your factory method will never make sense for it. 但是,由于C是封闭类型,因此我看不到您真正想要完成的工作,因此您的工厂方法将永远无济于事。

UPDATED 更新

The following might be closer to what you are looking for: 以下内容可能更接近您要寻找的内容:

public TAofT FactoryMethod<TAofT, T>() where TAofT : A<T>, new()
{
    return new TAofT():
}

public static void Main()
{
    A<string> first = FactoryMethod<A<string>, string>();
    A<int> second = FactoryMethod<B<int>, int>();
    A<D> third = FactoryMethod<C, D>();
}

But the factory method then seems redundant, since you could just do: 但是工厂方法似乎是多余的,因为您可以这样做:

public static void Main()
{
    A<string> first = new A<string>();
    A<int> second = new B<int>();
    A<D> third = new C();
}

UPDATE 2 更新2

Unless what you really want is this: 除非您真正想要的是:

public abstract class AEnum<T, T3> where T3 : B<T>, new()
{
    private static Func<A<T>> factoryMethod;

    public static readonly Level1 = new AEnum<T>(()=>new A<T>());
    public static readonly Level2 = new AEnum<T>(()=>new B<T>());
    public static readonly Level3 = new AEnum<T>(()=>new T3());

    protected AEnum(Func<A<T>> factoryMethod) { this.factoryMethod = factoryMethod; }

    public A<T> New() { return this.factoryMethod(); }
}

used like this: 像这样使用:

public class DEnum : AEnum<D, C>
{
}

with: 有:

public static void Main()
{
    A<D> first = DEnum.Level1.New();
    A<D> second = DEnum.Level2.New();
    A<D> third = DEnum.Level3.New();
}

But then you could not mix enum types, since the above is type constrained to D . 但是您不能混合枚举类型,因为上面的类型被限制为D

Or you could do: 或者您可以这样做:

public class OpenAEnum<T, T3> : AEnum<T, T3> where T3 : B<T3>
{
}

public class CInt : B<int> {}
public class Cstring : B<string> {}

with: 有:

public static void Main()
{
    A<string> first = OpenAEnum<string, CString>.Level1.New();
    A<int> second = OpenAEnum<int, CInt>.Level2.New();
    A<D> third = OpenAEnum<D, C>.Level3.New();
}

What is it that you are trying to do? 您正在尝试做什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM