2009-08-03 34 views
1

超载泛型方法我有方法,通过它传递函数求代表至极用户转换一些输入值返回新值(非常超过简化了什么,我想实现)特定数据类型

public L Coerce<L>(string value, Func<string, L> coercer) 
    { 
     return coercer(value); 
    } 

    Coerce<int>("123", v => int.Parse(v)); 

这是好的,但是我也希望能够编写重写行为为特定类型的如方法...

public int Coerce<int>(string value) 
    { 
     return Coerce<int>(value, v => int.Parse(v)); 
    } 

所以基本上调用

Coerce<int>("123"); // equivalent Coerce<int>("123", v => int.Parse(v)); 

将节省我不得不为每个Coerce重写int.Parse。当然,这应该再扩展到处理

public decimal Coerce<decimal>(string value) 
    { 
     return Coerce<decimal>(value, v => int.Parse(v)); 
    } 

等等等等

可以这样做整齐?

詹姆斯

+0

您不必使用拉姆达式呼叫:您还可以拨打强制( “123”,int.Parse)。 – 2009-08-03 12:29:37

+0

好吧,这有点更好,但我宁愿不必事件添加int.Parse在最后如果可能? – 2009-08-03 12:35:07

回答

6

好吧,如果你真的不想做

Convert.ToInt32(value) 

,那么这将做什么你在问:

public T Coerce<T>(string value) where T : IConvertible 
{ 
    return (T)(((IConvertible)value).ToType(typeof(T), 
     CultureInfo.InvariantCulture)); 
} 

因此:

int x = Coerce<int>("123"); 

byte b = Coerce<byte>("123"); 

,如果你试着将其转换为不可兑换的类型,例如这会给你一个编译时错误:

var x = Coerce<MyClass>("123"); //compile-time error 

在这种情况下,您强制呼叫者使用您的超载。

1

你可以使用非通用版本:

public int CoerceInt32(string value) 
{ 
    return Coerce(value, int.Parse); 
} 
+0

是的,我可以。我认为这将是最直接的方法,但我想知道如果我能以更通用的方式处理它? – 2009-08-03 12:29:53

+0

原因是我实际上是通过扩展方法做到这一点,并且我不想用不必要的方法溢出课程(所以在这种情况下坚持一个或两个会更好) – 2009-08-03 12:31:27

0

这种方法的目的是什么?

你为什么要这样写:

int x = Coerce<int>("123", v => int.Parse(v)); 

,而不是仅仅这一点:

int x = int.Parse("123"); 

但是,要回答你的问题,不,不 “整齐”。 .Parse是int和decimal类型的静态方法,因此不适用于您的泛型类型。

您可以希望得到的最好的结果是为每个要处理的类型编写一个重载,或者在您的方法中编写反射代码以确定要调用哪个静态方法。

就这样你进入一个问题,当你这样写:

MyMagicType x = Coerce<MyMagicType>("123"); 

什么呢?你会认为MyMagicType有一个.Parse方法吗?

0

恐怕C#没有像C++一样的模板重写。我碰到过类似的情况,我不得不解决它的方法是在运行时检查类型:

public void DoStuff<T>(Dictionary<object, T> arg) { 
    // .... 
    if (typeof(T) == typeof(ClassA)) { 
     DoStuff((Dictionary<object, ClassA>)arg); 
    } 
    else (typeof(T) == typeof(ClassB)) { 
     DoStuff((Dictionary<object, ClassB>)arg); 
    } 
    else { 
     throw new ArgumentException("T must be ClassA or ClassB"); 
    } 
}