也许这是一个简单的新手C#问题,但也就是这样 - 它将是我的其他问题的新突破,这是非常困难的,没有人知道他们的答案。 :)
假设我在C#中有一个泛型类型:
Thing<T>
让我们说我想用静态工厂方法制作一个东西。在Java中,这不是问题:
public static <T> Thing<T> createThing()
{
return flag ? new Thing<Integer>(5) : new Thing<String>("hello");
}
我如何在C#中执行此操作?感谢。
答案 0 :(得分:4)
如果要使用许多不同的模板参数之一返回模板化类的实例,一种方法是使用抽象基(或接口):
abstract class UntypedThing { }
class Thing<T> : UntypedThing
{
public Thing(T t) { }
}
class Foo
{
public static UntypedThing createThing(bool flag)
{
if (flag)
return new Thing<int>(5);
else return new Thing<String>("hello");
}
}
UntypedThing
类将包含尽可能多的代码,不依赖于模板类型。理想情况下,Thing
类只包含依赖于模板类型的代码。工厂类Foo
始终返回前者。
答案 1 :(得分:3)
理论上你可以使用反射来构建正确的泛型类型,但它对你来说是没用的,因为在某些时候你需要将它转换为不太具体的类型。
public class ThingFactory {
public object Create(bool flag) {
Type outputType = null;
if(flag) {
outputType = typeof(string);
} else {
outputType = typeof(int);
}
return Activator.CreateInstance(typeof(Thing<>).MakeGenericType(outputType));
}
}
正如您所看到的,执行此操作的值大约为零,因为您需要将返回类型强制转换为所需的类型,这意味着确定它的逻辑需要位于Create
方法之外。
我会使用Reinderien的方法,并且具有非通用基础。这是最理智和最惯用的方法。
答案 2 :(得分:0)
哦,当我只是想做一些简单的事情时,我遇到了麻烦。
事实证明C# 4 allows this sort of covariance有点像。首先,我必须使Thing成为一个接口并指定“out”泛型参数:
public interface Thing<out T> {...}
但如果我做某些事情,C#就不会让我使用协方差。例如,如果我尝试从界面返回T:
public interface Thing<out T>
{
public T GetT();
即使我设法与Thing合作,我该怎么办呢?
Thing<object> thing=createThing();
编译器告诉我无法从使用中推断出类型。
假设我说搞整个T事件并使工厂方法返回类型对象的东西:
public static Thing<object> createThing() {...}
很好,但现在我把它放在哪里?
IList<Thing<object>> list=new List<Thing<object>>();
Thing<object> thing=createThing();
list.Add(thing);
是的,我必须说这是一个带有Object类型的Th的列表,因为C#没有通配符类型。
如果这是Java,我只想说:
public class Thing<T> {...}
public static <T> Thing<T> createThing() {...}
List<?> things=new ArrayList<Thing<?>>();
Thing<?> thing=createThing();
things.add(thing);
如果我想通过说T必须属于特殊类型而需要额外的安全性,我会说:
public static <T extends MyBaseType> Thing<T> createThing() {...}
List<? extends MyBaseType> things=new ArrayList<Thing<? extends MyBaseType>>();
Thing<? extends MyBaseType> thing=createThing();
things.add(thing);
然后,当我获得更多信息时,我会弄清楚T是什么。
这一切似乎归结为C#中不完整的通用协方差以及缺少C#通用通配符。 (我仍然认为这不是一个擦除问题。)
那我该怎么办?唯一简单的事情似乎是遵循Reinderien的答案并拆分出一个非通用的基类。
(我想知道在这个非泛型基类中我是否可以使用对象getValue()然后在子类中使用协方差来返回T getValue()?Ack,我已经厌倦了 - 我会离开那一天。)