在generics方法中将值转换为T.

我有一个creaky属性映射的接口:

interface IPropertyMap { bool Exists(string key); int GetInt(string key); string GetString(string key); //etc.. } 

我想创建一个像这样的扩展方法:

 public static T GetOrDefault(this IPropertyMap map, string key, T defaultValue) { if (!map.Exists(key)) return defaultValue; else { if (typeof(T) == typeof(int)) return (T)map.GetInt(key); //etc.. } } 

但编译器不会让我转向T.我尝试添加where T : struct但这似乎没有帮助。

我错过了什么?

我相信这是因为编译器不知道它需要执行什么类型的操作。 IIRC,如果你介绍拳击,你可以让它工作:

 if (typeof(T) == typeof(int)) return (T)(object)map.GetInt(key); 

但就性能而言,这并不理想。

不幸的是,我认为这只是generics的限制。

GetIntGetString等在内部做什么? 可能有其他选项涉及Convert.ChangeType(...)TypeDescriptor.GetConverter(...).ConvertFrom(...)和单个强制转换,使用“对象”索引器:

例如,如果对象已经正确输入:

 public T GetOrDefault(this IPropertyMap map, string key, T defaultValue) { return map.Exists(key) ? (T)map[key] : defaultValue; } 

或者如果它们存储为字符串并需要转换,则涉及:

 T typedVal = (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(map[key]); 

我想这只是一个错字,但bool GetInt(string key)似乎很奇怪。 它应该是int GetInt(string key) ,或者更好的是int GetInt32(string key)

接下来,Jon已经注意到你的代码需要装箱,所以这就是你所做的。

最后,在IPropertyMap接口中添加一个“catch-all”方法 – 比如object GetValue(string key)然后重写GetOrDefault以使用此方法而不是无限且容易出错的Type比较:

 else return (T)(object)map.GetValue(key); 

仅供参考,我发现了另一个具有GetType()和GetAsObject()方法的接口,它允许我集成这些答案的元素来执行此操作:

 public static T GetOrDefault(this IInfosContainer container, string key, T defaultValue) { //I just read p273 of C# in Depth, +1 Jon Skeet :) if (container == null) throw new ArgumentNullException("container"); if (container.Exist(key)) { if (container.GetType(key) != typeof(T)) throw new ArgumentOutOfRangeException("key", "Key exists, but not same type as defaultValue parameter"); else return (T)container.GetAsObject(key); } else return defaultValue; } 

纯粹主义者会注意到我不是’一个声明’学校的’大括号……

我认为这不是一个好方法。 你无法控制T是什么。 例如

float value = map.GetOrDefault(“blah”,2.0);

不会编译,因为不能隐式地将类型’double’转换为’float’。 存在显式转换(您是否缺少转换?)另一个失败点是所需的默认值为null。 这种方法使开发人员受编译器的支配,以解决它认为开发人员的意图。

如果可以更改接口,则添加GetObject方法。 由于您使用的是扩展方法,我假设您不能将对象强制转换为int。 无论哪种方式改变方法看起来像

public static void GetOrDefault(此IPropertyMap映射,字符串键,ref T值){if(map.Exists(key)){if(typeof(T)== typeof(int)){value =(T)(object)map .GetInt(键); } value = default(T); //这只是一个非常好的因为我很懒,//在这里添加实际代码。 并且这样调用

  PropertyMap map = new PropertyMap(); float value = 2.0f; map.GetOrDefault("blah", ref value); 

我讨厌ref params,但我明白了这一点。 注册表是这种方法何时有用的经典示例。 上面的代码强制dev用户明确指定输出的类型并保留概念默认值。