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.
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. You need to specify the generic parameter of A
in order to use it as a type.
In this case, because C
is B<D>
, and B<D>
is A<D>
, then you would use A<D>
as the return type.
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.
C
is a sub class of the bound type 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>
. 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.
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>
.
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:
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.
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.
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
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
.
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?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.