类型未知的泛型
本文关键字:泛型 未知 类型 | 更新日期: 2023-09-27 18:12:46
我正在创建一个设置类,如下所示:
class Setting<T> {...}
我将所有设置存储在树中,如下所示:
class SettingsNode {
public Setting<> setting;
public Setting<> child;
public Setting<> sibling;
}
由于<>
。我可以有多种类型(Setting<int>
, Setting<string>
等),所以我不知道如何创建SettingsNode。
所以我改成:
class SettingsNode {
public object setting;
public object child;
public object sibling;
}
但是我在转换到正确的类型时遇到了麻烦:
// Create a setting from a type name as text
SettingsNode tmp = new SettingsNode();
Type genericType = typeof(Setting<>);
Type[] typeArgs = { Type.GetType("System.Int32") };
Type cType = genericType.MakeGenericType(typeArgs);
tmp.setting = Activator.CreateInstance(cType);
// Here's where I have a problem
Type baseType = typeArgs[0];
((Setting<baseType>)(tmp.setting)).SomeFunction();
最后一行的错误是:
类型或命名空间名称'baseType'无法找到(您是否缺少using指令或程序集引用?)
我该怎么做?谢谢!
一个选项是您可以继续使用dynamic
关键字:
class SettingsNode
{
public dynamic setting;
public dynamic child;
public dynamic sibling;
}
你可以这样做:
SettingsNode tmp = new SettingsNode();
tmp.setting = new Setting<int>();
tmp.setting.SomeFunction()
无需使用反射
为什么不设置:
class SettingsNode<T> {
public Setting<T> setting;
public Setting<T> child;
public Setting<T> sibling;
}
如果你真的想走这条路,创建一个抽象的非泛型基类abstract class Setting
和一个泛型Setting<T> : Setting
。
object
而不是T
定义非泛型中的所有常用方法,并将泛型作为适配器使用,该适配器调用super
的方法/属性并在每个方法/属性中强制转换object<=>T。我不认为泛型是正确的工具。泛型是一个编译时工具:如果在编译时不知道泛型类型,则没有比非泛型类型更有利的地方。
因此,除非您计划在代码中显式地使用Setting<Int32>
和Setting<String>
,否则在这里使用泛型是没有意义的,您不妨坚持使用Setting
。
泛型不能这样做。
泛型的全部意义在于在类型系统内指定类型参数& &;在编译时。
您试图使这些字段没有已知类型。
相反,您应该使泛型类继承非泛型SettingsBase
基类(或接口),并使该类型的字段。
调用代码可以将它们强制转换回实际的泛型类型。
如果Setting<T>
定义了方法:
public T Transform(T value);
…你可以定义一个Setting<?>
类型的字段,那么Transform
会接受什么类型的参数?object
是所有可能的T
所共有的唯一类型。这样就失去了类型安全性。Transform
返回什么类型的参数?同样,object
,所以你必须强制转换所有内容
您应该将每个泛型类实例视为不同的类型:手动将Setting<T>
类复制为SettingOfInt32
并将所有T
替换为Int32
,这可以通过泛型语法Setting<Int32>
自动完成。因此,不要认为Setting<Int32>
和Setting<String>
都是Setting<T>
,而应该认为SettingOfInt32
和SettingOfString
都是从Object
派生出来的。
想象一下,您希望能够在字段中放置类型为SettingOfInt32
和SettingOfString
的对象,该字段必须具有什么类型?当然,是两种类型都通用的类型,比如object
。现在你可能意识到,如果你想调用SettingOfInt32
和SettingOfString
中存在的任何方法,你应该将该方法移动到一个公共基类中,例如Setting
。那么您的字段类型必须是Setting
,并且一切都很好。
public class Setting<T> : Setting { }
public abstract class Setting { }
这也迫使您处理类似上面的Transform
示例的事情。您是否将其包含在公共基类中?也许是,也许不是。你用什么类型代替T
?也许是object
,也许是别的什么。你做显式类型检查吗?可能…
如前所述,我认为不应该在这种情况下使用泛型。如果你想要/需要坚持它,你可以尝试使用具有多个泛型的类。
public class SettingsNode<TSetting, TChild, TSibbling>
{
public Setting<TSetting> Setting { get; set; }
public Setting<TChild> Child { get; set; }
public Setting<TSibbling> Sibling { get; set; }
}
public class Setting<T>
{
public T Value;
}
SettingsNode<String, int, int> node = new SettingsNode<string, int, int>();
node.Sibling = new Setting<int>();
node.Setting = new Setting<string>();
node.Child = new Setting<int>();
有一次当我不知道该期待什么类型时,我采用了另一种方法。这涉及到动态关键字的使用,所以需要c# 4.0+