2013-10-07 120 views
2

我想创建一个这样的泛型函数,我打算实例化基本类型,大多数是DateTime,int和字符串。强制C#泛型类型的任意函数

static T MyParameter<T>(string value, T defaultValue) 
{ 
    return value.StartsWith("$$") ? defaultValue : T.Parse(value); 
} 

这不会编译,因为不能保证T会有“解析”。

有没有一种“直接”的方式来实现它? (我的意思是,避免反思或代表做肮脏的工作)。

我找不到任何约束T会做的伎俩。

+0

恐怕没有。 – MarcinJuraszek

+1

我的一般做法是将'T'约束为'IConverible',并使用'Convert.ChangeType'并将其转换为T来处理。但是,如果您的价值以$$开头,除非您剥离美元符号,否则几乎总是无法解析。 – vcsjones

+0

@vcsjones我认为这就是为什么当'value'以'$$'开始时他返回'defaultValue'的原因。 – MarcinJuraszek

回答

6

你可以在分析方法通过为通用情况:

static T MyParameter<T>(string value, T defaultValue, Func<string, T> parse) 
{ 
    return value.StartsWith("$$") ? defaultValue : parse(value); 
} 

但为了方便起见,你可能要为您计划使用的最常见类型的提供重载:

static int MyParameter(string value, int defaultValue) 
{ 
    return MyParameter(value, defaultValue, int.Parse); 
} 
static DateTime MyParameter(string value, DateTime defaultValue) 
{ 
    return MyParameter(value, defaultValue, DateTime.Parse); 
} 
static string MyParameter(string value, string defaultValue) 
{ 
    return MyParameter(value, defaultValue, x => x); 
} 

如果你真的不喜欢这样,你可以使用反射,但我不会推荐它:

static T MyParameter<T>(string value, T defaultValue) 
{ 
    if (value.StartsWith("$$")) 
    { 
     return defaultValue 
    } 

    var method = typeof(T).GetMethod("Parse", new[] { typeof(string) }); 
    return (T)method.Invoke(null, new[] { value }); 
} 
+0

注意:如果您将'method'缓存在字典中,则每个值为T的反射实际上可以更快一些。 (更多的时间用于验证* right *方法)当然,基本类型都实现'IConvertible'。 – 2013-10-08 13:35:28

1

这应该这样做:

static T MyParameter<T>(string value, T defaultValue) 
{ 
    return (T) (value.StartsWith("$$") ? defaultValue : Convert.ChangeType(value, typeof (T))); 
} 
2

在泛型上使用约束怎么样?

http://msdn.microsoft.com/en-us/library/d5x73970.aspx

所以,你的方法就变成了:

static T MyParameter<T>(string value, T defaultValue) where T : IParseable 
{ 
    return (T)(value.StartsWith("$$") ? defaultValue : defaultValue.Parse(value)); 
} 

当然,这意味着使用的所有类型必须实现IParseable。

+0

这是正确的方法。基本上,您需要使用该类型的协方差来确保它符合您尝试调用的内容。 – Alex

+0

这实际上不会编译。 ** 1)**您试图在'T',** 2)**上静态调用'Parse',除非'IParseable'是通用的(例如'where T:IParseable '),那么返回值'Parse'可以在没有强制转换的情况下返回,并且** 3)**即使您修复了这些问题,您仍然无法使用内置数据类型('int','DateTime',''字符串')由.NET提供,因为它们不实现自定义'IParseable'接口。 –

+0

是的,你说得对。我修复了#1和#2。 #3,你完全正确。这是这个代码的问题。你基本上必须为所有烦人的基本数据类型编写包装。 – Zippit