2

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

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

我怎样才能做到这一点?谢谢!

4

7 回答 7

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

无需使用反射

于 2013-05-08T15:07:16.953 回答
1

如果您真的想走这条路,请创建一个抽象的非泛型基类abstract class Setting和一个泛型Setting<T> : Setting. object使用而不是 a定义非泛型方法中的所有常用方法,T并将泛型方法用作调用super的方法/属性并在每个方法/属性中强制转换 object<=>T 的适配器。

于 2013-05-08T15:22:23.453 回答
1

为什么没有:

class SettingsNode<T> {
    public Setting<T> setting;
    public Setting<T> child;
    public Setting<T> sibling;
}
于 2013-05-08T15:07:40.403 回答
0

我认为泛型不是解决此问题的正确工具。泛型是一种编译时工具:如果泛型类型在编译时未知,则与非泛型类型相比没有优势。

因此,除非您打算在代码中显式使用Setting<Int32>和,否则Setting<String> 在这里使用泛型是没有意义的,您不妨坚持使用Setting.

于 2013-05-08T15:08:23.923 回答
0

泛型无法做到这一点。
泛型的全部意义在于在类型系统中指定类型参数——在编译时。
您正在尝试使这些字段没有已知类型。

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

于 2013-05-08T15:09:57.437 回答
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>();

当我不知道该期待什么类型时,这是我曾经采用的另一种方法。这里涉及到动态关键字的使用,所以需要c# 4.0+

于 2013-05-10T04:31:38.970 回答
0

如果Setting<T>定义了一个方法:

public T Transform(T value);

...并且您可以定义一个 type 字段,那么将接受Setting<?>哪种类型的参数?是所有可能的唯一类型。所以你失去了所有类型的安全性。什么类型的参数会返回?再次,,所以你必须铸造一切。TransformobjectTTransformobject

您应该将每个泛型类实例视为不同的类型:手动将Setting<T>类复制为SettingOfInt32并将所有替换TInt32,只是通过泛型语法自动化Setting<Int32>。因此,与其认为Setting<Int32>and Setting<String>are both Setting<T>,不如认为你 haveSettingOfInt32并且SettingOfStringthat are both from Object

想象一下,您希望能够将类型SettingOfInt32和类型的对象SettingOfString放入一个字段中,该字段必须具有什么类型?当然,两者都通用的类型,例如object. 现在您可能会意识到,如果您想调用两者中存在的任何方法SettingOfInt32SettingOfString,您应该将该方法移至公共基类,例如Setting。那么您的字段类型必须是Setting并且一切正常。

public class Setting<T> : Setting { }

public abstract class Setting { }

Transform这也迫使你处理上面例子中的事情。您是否将其包含在公共基类中?也许,也许不是。你用什么类型代替T?也许object,也许是别的东西。您是否进行显式类型检查?可能...

于 2013-05-08T15:44:53.803 回答