这很少需要,但有时仍然有用。
假设有阶段。在第一阶段,您可以访问某些类型T
,但您现在无法使用它。然后,稍后,执行第二阶段,并且必须执行涉及第一阶段中已知的类型T
的事情。
System.Type
对象不是解决方案,因为与真实类型相比,它们非常有限。例如。你不能写Type type = typeof(int); new List<type>()
。
让我们正确化问题:
public static Something Store<T>() {
//store T and return it
}
public static void Use(Something smth) {
//do something with T (e.g. create a `List<T>` instance and pass it to Console.WriteLine)
}
我该如何做到这一点?
更新:
一个用例示例:假设我们有两种不同的独立算法。一个选择元素数据类型(int
/ float
/ decimal
等),另一个选择容器类型(List<>
/ LinkedList<>
/ {{1} }/等等)。每种类型都有许多种类,并且不知道整个可能的类型集。现在我们需要编写创建类型化容器的中心代码片段(例如HashSet<>
)。我们不能将这些代码放入任何一种类型选择算法中。我们想要做的是让算法以某种方式存储和返回所选类型。这通常通过类型枚举,HashSet<decimal>
对象等来完成。但我想要一个静态的强类型编译时解决方案。
答案 0 :(得分:2)
由于C#不允许存储类型,我们需要存储“使用特定类型的能力”。
首先,我们需要一种表达类型相关操作的方法(例如,创建List<T>
实例并将其传递给Console.WriteLine
)。不幸的是.Net不允许为“非特定”泛型方法创建委托,但是我们可以通过接口获得类似的功能,因为它们支持泛型方法(参见Emulating delegates with free generic type parameters in C#)。
interface IGenericAction {
void Do<T>();
}
class MyGenericListAction : IGenericAction {
public void Do<T>() {
Console.WriteLine(new List<T>());
}
}
我们存储“使用特定类型执行某些类型相关操作的能力”:
public static Action<IGenericAction> Store<T>() {
return action => action.Do<T>(); //Returns a function that, given a type-dependent action (IGenericAction), invokes it with type T
}
然后我们可以使用存储的类型:
public static void Use(Action<IGenericAction> genericInvoker) {
genericInvoker(new MyGenericListAction()); //genericInvoker will call MyGenericListAction.Do<T>() using the stored type T
}
让我们测试一下:
var storedType = TypeHelpers.Store<int>();
Use(storedType);
//System.Collections.Generic.List`1[System.Int32] is printed on the console
答案 1 :(得分:0)
C#(或一般的.NET)是强类型的。这特别适用于泛型。如果创建泛型类型的实例,则type参数将在编译时固定。我不是百分百肯定它,但我认为,编译内部为具有特定类型参数的泛型生成一个全新的类型。这使得无法存储类型并在以后使用它来创建List的实例。无论如何,在调用Store时,你必须知道T,从那时起我们就会被强类型化。你可以用
public static Something<T> Store<T>()
{
//whatever
}
然后致电
public static void Use<T>(Something<T> yourStoredSomething)
{
yourStoredSomething.DoSomething();
}
无论如何,你仍然无法动态使用T.另一方面,如果我们从接口
派生出通用的东西interface ISomething
{
void DoSomething();
}
我们可以做到
public static ISomething Store<T>()
{
return new Something<T>();
}
并且可以使用以下内容:
ISomething mySomething = null;
if(t == "string")
{
mySomething = Storer.Store<string>();
}
else if(t == "int")
{
mySomething = Storer.Store<int>();
}
请注意,这是您的问题的解决方案,但可能不是最好的解决方案。正如我之前所说的那样,泛型是非常类型的,这不是他们应该使用的方式。我以一种我厌恶的方式滥用泛型,我提供的解决方案主要是为了学术目的,而不是用于真正的程序。可能你应该改变你的方法来解决你遇到的问题,以实现更好的设计。