未知类型的泛型

时间:2013-05-08 15:05:45

标签: c# generics

我正在创建一个类似的设置类:

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指令或程序集引用?)

我该怎么做?谢谢!

7 个答案:

答案 0 :(得分:2)

一种选择是您可以继续使用dynamic关键字:

class SettingsNode
{
    public dynamic setting;
    public dynamic child;
    public dynamic sibling;
}

所以你可以这样做:

SettingsNode tmp = new SettingsNode();
tmp.setting = new Setting<int>();

tmp.setting.SomeFunction()

无需使用反射

答案 1 :(得分:2)

为什么没有:

class SettingsNode<T> {
    public Setting<T> setting;
    public Setting<T> child;
    public Setting<T> sibling;
}

答案 2 :(得分:1)

如果你真的想要沿着这条路线走下去,那就制作一个抽象的非通用基类abstract class Setting和一个通用的Setting<T> : Setting。使用object而不是T定义非泛型方法中的所有常用方法,并使用泛型方法作为调用super的方法/属性的适配器并执行转换对象&lt; = &gt;每个方法/属性中的T.

答案 3 :(得分:0)

我不认为仿制药是正确的工具。泛型是编译时工具:如果在编译时不知道泛型类型,则没有优于非泛型类型的优势。

因此,除非您计划明确地在代码中使用Setting<Int32>Setting<String>,否则在此处使用泛型毫无意义,您也可以坚持使用Setting

答案 4 :(得分:0)

泛型不能这样做。
泛型的全部意义是在类型系统中指定类型参数 - 在编译时 你试图让这些字段没有已知类型。

相反,您应该使泛型类继承自非泛型SettingsBase基类(或接口),并创建该类型的字段。
调用代码可以将它们转换回实际的泛型类型。

答案 5 :(得分:0)

如果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>,而不是SettingOfInt32SettingOfString都是Object。 }。

想象一下,您希望能够将SettingOfInt32SettingOfString类型的对象放在一个字段中,该字段必须具有哪种类型?当然,这两种类型都是共同的类型,例如object。现在您可能会意识到,如果要调用SettingOfInt32SettingOfString中存在的任何方法,则应将该方法移动到公共基类,例如: Setting。那么你的字段类型必须是Setting,一切都很好。

public class Setting<T> : Setting { }

public abstract class Setting { }

这也迫使您处理上述Transform示例之类的事情。你把它包含在公共基类中吗?也许,也许不是。您使用什么类型而不是T?也许是object,也许还有别的。你做了明确的类型检查吗?可能...

答案 6 :(得分:0)

如上所述,我不认为应该在这种情况下使用泛型。 如果你想/需要坚持下去,你可以尝试使用具有多个泛型的类。

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>();

Here's a different approach 当我不知道期待什么类型时,我服用了一次。这涉及到动态关键字的使用,因此需要c#4.0 +