4

Is it possible to create a generic Func<T><T>, as in a Func that accepts a generic parameter and needs to return the type of that generic parameter?

In other words, can I do this?

Func<T> createNull = () => default(T);

Note that I don't have any context from a containing class or method, so I'd want to do:

var user = createNull<User>();

Here's a bit more info about what I'm trying to do.(note that the syntax is off, because I don't know how to do it nor whether it's possible):

Func<TQuery, TResult><TQuery, TResult> query = q => 
    (TResult) handlers[Tuple.Create(typeof(TQuery), typeof(TResult))](q);

where handlers is declared as following:

var handlers = new Dictionary<Tuple<Type, Type>, Func<TQuery, TResult><TQuery, TResult>();
// examples
handlers.Add(Tuple.Create(typeof(ById), typeof(User)), 
             idQuery => new User());
handlers.Add(Tuple.Create(typeof(ByName), typeof(Customer)), 
             otherQuery => new Customer());

Then I'd like to use query like this:

User result = query<User, IdQuery>(new ById{Id = 1});
Customer result1 = query<Customer, ByName>(new ByName());
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
Kenneth
  • 28,294
  • 6
  • 61
  • 84
  • 1
    Just some advice. Rather than writing out stuff like `Dictionary, Func>` over and over again, alias it at the top of the file with `using HandlerCache = Dictionary, Func` and throughout that file you can refer to it as simply `HandlerCache` (though in every other way it's the ugly complex type). Not quite as slick as F# but still helpful – George Mauer Nov 20 '14 at 01:35
  • The syntax `Func` in the title and opening sentence doesn't make sense. Did you perhaps mean `Func` or `Func` (as you demonstrate later in your question)? – DavidRR Sep 22 '15 at 18:17

2 Answers2

4

No, but you can put it in static class that will give you almost what you want:

static class CreateNull<T>
{
   public static Func<T> Default = () => default(T);
}

var createNull = CreateNull<User>.Default;
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • 1
    or `public static Func Default() { return () => default(T) }` and then the generic can be on the method and not on the class. You would invoke as `Func builder = CreateNull.Default()` – George Mauer Nov 20 '14 at 01:36
  • Thanks, that was what I was trying to avoid, I wanted multiple of these differently typed `Func`'s in a single class, but I already figured it probably wasn't possible. – Kenneth Nov 20 '14 at 01:48
0

No. Generics can be applied to methods, delegates and classes only.

Generics are a compiler feature that allow you to write one method and the compiler will generate a method for each set of types required. So if you write:

public T DoSomething<T>(T input)

and then use it:

int result1 = DoSomething(1);
double result2 = DoSomething(2.0);
MyType result3 = DoSomething(new MyType());

For each of the lines above the JIT generates a new overload of the method.

Lambdas are typed, so they generate a specific overload of the delegate in question:

// Given generic Func<TInput, TResult>
Func<int, string> foo = (s) => Integer.parseInt(s);
  • *"Generics are a compiler feature that allow you to write one method and the compiler will generate a method for each set of types required."* This is not true. .Net is not c++, IL supports generics natively. [You can prove this easily with ILSpy](http://content.screencast.com/users/togakangaroo/folders/Jing/media/cd902c22-c1bb-40b0-9c89-bbd5e275d0d3/2014-11-19_1952.png) – George Mauer Nov 20 '14 at 01:54
  • 1
    @GeorgeMauer thanks for correcting me! I assumed wrongly. The JIT does it as per this answer: http://stackoverflow.com/a/5342424/545680 –  Nov 20 '14 at 02:53
  • Interesting, if you read the quote he's actually not saying this is what the JIT does exactly. It just creates copies as an optimization, it's not a key part of the implementation. Notice that he says all reference types (which is 95% what we care about) use the same IL code, it's only the native types that get their own copies. – George Mauer Nov 20 '14 at 05:51
  • Yep. This is why .NET doesn't suffer the boxing/unboxing penalty for using generics on primitives like Java does. –  Nov 20 '14 at 06:15