James Hughes
James Hughes

Reputation: 6194

Overload Generic Method for Specific Data Type

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

Answers (4)

Matt Howells
Matt Howells

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

thecoop
thecoop

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

Lasse V. Karlsen
Lasse V. Karlsen

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

Tommy Carlier
Tommy Carlier

Reputation: 8159

You could use a non-generic version:

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

Upvotes: 1

Related Questions