45

I like to send a generic type converter function to a method but I can't figure out how to do it.

Here's invalid syntax that explains what I like to achieve, the problem is I don't know how to specify the generic type together with my func:

public void SomeUtility(Func<T><object,T> converter)
{
    var myType = converter<MyType>("foo");
}

Edit (see also my discussion in the comments with Lawrence) : By "generic type converter" I meant I would like to pass in a converter that can convert to any strong type <T> (not object), so the next line in my method could be:

var myOtherType = converter<MyOtherType>("foo");

The delegate I like to pass as a parameter would look something like this:

private delegate TOutput myConverterDelegate<TOutput>(object objectToConvert);

This is more a syntax / C# exploration now, to get things done I will probably use an interface instead, but I do hope this is possible to accomplish with a func/delegate.

Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
joeriks
  • 3,382
  • 8
  • 32
  • 42
  • Is the fact you've specified a type inside the method body significant? Are you implying this method may need to make conversions against multiple types, rather than one specific type defined by the caller? – Lawrence Wagerfield Sep 25 '12 at 08:39
  • Yes, that was what I tried to express as a "generic type converter" so the next line could be var myOtherType = converter("foo"); – joeriks Sep 25 '12 at 08:43
  • Ok - then I think you'll find my answer useful :) – Lawrence Wagerfield Sep 25 '12 at 08:44

4 Answers4

32

You cannot have instances of generic functions or actions - all type parameters are defined upfront and cannot be redefined by the caller.

An easy way would be to avoid polymorphism altogether by relying on down-casting:

public void SomeUtility(Func<Type, object, object> converter)
{
    var myType = (MyType)converter(typeof(MyType), "foo");
}

If you want type safety, you need to defer the definition of the type parameters to the caller. You can do this by composing a generic method within an interface:

public void SomeUtility(IConverter converter)
{
    var myType = converter.Convert<MyType>("foo");
}

interface IConverter
{
   T Convert<T>(object obj);
}

Edit:

If the 'converter type' is known at the call-site, and only this type will be used inside the utility method, then you can define a generic type on the method and use that, just like other posters have suggested.

Lawrence Wagerfield
  • 6,471
  • 5
  • 42
  • 84
  • Ok thanks, yes I will probably just use an interface, thanks for pointing me to that direction. But, out of interest, shouldn't a delegate / a func be able to pass on a generic type? Described as a delegate I guess I would write it as : private delegate TOutput myConverterDelegate(object objectToConvert); - but when I try to use that as a parameter I get "requires 1 type arguments" – joeriks Sep 25 '12 at 09:09
  • 1
    You can certainly *define* generic delegates, after all, that's exactly what Func and Action are. They are treated as *generic definitions*, just like generic interfaces and classes are. However, you cannot use *generic definitions* in method signatures, only parameterized *generic types*. Quite simply you cannot do what you are trying to achieve with a delegate alone. – Lawrence Wagerfield Sep 25 '12 at 09:34
18
public void SomeUtility<T>(Func<object, T> converter)
{
    var myType = converter("foo");
}

and then:

SomeUtility(arg => new MyType());

The generic type inference will work in this case.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
9

You need to make SomeUtility generic as well. Doing this and fixing the syntax gives:

public void SomeUtility<T>(Func<object,T> converter)
{
    var myType = converter("foo");
}
Jon
  • 428,835
  • 81
  • 738
  • 806
4

You have to know the T type at compile-time to use it. The T can either be specified at class-level or at method-level.

class SomeClass<T> {
    public void SomeUtility(Func<object, T> converter) {
        var myType = converter("foo"); // Already is the T-type that you specified.
    }
}

or

public void SomeUtility<T>(Func<object, T> converter) {
    var myType = converter("foo"); // Already is the T-type that you specified.
}
Maarten
  • 22,527
  • 3
  • 47
  • 68