Reputation: 6194
I have method that transforms some input value by the user passing it a Func delegate wich returns the new value (very over simplified for what I am trying to achieve)
public L Coerce<L>(string value, Func<string, L> coercer)
{
return coercer(value);
}
Coerce<int>("123", v => int.Parse(v));
This is fine however I also want to be able to write methods that override the behaviour for a specific type eg...
public int Coerce<int>(string value)
{
return Coerce<int>(value, v => int.Parse(v));
}
So basically calling
Coerce<int>("123"); // equivalent Coerce<int>("123", v => int.Parse(v));
will save me having to re-write the int.Parse for every Coerce. Of course this should then extend to handle
public decimal Coerce<decimal>(string value)
{
return Coerce<decimal>(value, v => int.Parse(v));
}
Etc etc.
Can this be done neatly?
James
Upvotes: 1
Views: 1729
Reputation: 41276
Well, if you really don't want to do
Convert.ToInt32(value)
Then this will do what you are asking:
public T Coerce<T>(string value) where T : IConvertible
{
return (T)(((IConvertible)value).ToType(typeof(T),
CultureInfo.InvariantCulture));
}
Hence:
int x = Coerce<int>("123");
or
byte b = Coerce<byte>("123");
This will give you a compile-time error if you try to coerce to a non-convertible type, for example:
var x = Coerce<MyClass>("123"); //compile-time error
In which case you force the caller to use your Coerce(string value, Func<string,T> coercer)
overload.
Upvotes: 6
Reputation: 46128
I'm afraid C# doesnt have template overriding like in C++. I came across a similar situation, and the way I had to work around it is to check the type at runtime:
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");
}
}
Upvotes: 0
Reputation: 391456
What is the purpose of this method?
Why do you want to write this:
int x = Coerce<int>("123", v => int.Parse(v));
instead of just this:
int x = int.Parse("123");
However, to answer your question, no, not "neatly". .Parse
is a static method on the int and decimal types, and thus not available through your generic type.
The best you can hope for is to either write one overload per type you want to handle, or to write reflection code inside your method to figure out which static method to call.
And thus you get into a problem when you write this:
MyMagicType x = Coerce<MyMagicType>("123");
what then? Will you assume that MyMagicType has a .Parse method?
Upvotes: 0
Reputation: 8159
You could use a non-generic version:
public int CoerceInt32(string value)
{
return Coerce(value, int.Parse);
}
Upvotes: 1