6

I have the following function in c#:

bool Handle<TCommandHandler, TModel>(TModel model) where TCommandHandler : ICommandHandler<TModel> {
    // ...
    _container.Resolve<TCommandHandler>();
    // ...
}

Since TModel is clear from a function parameter I want some way to not specify its type when calling a function. Ideally I want to call it like:

Handle<MyCommandHandler>(model);

Since this is probably impossible, I came up with the following:

HandleTemp<TModel> Handle<TModel>(TModel model) {
    return new HandleTemp<TModel>(model);
}

public class HandleTemp<TModel> {
    private TModel _model;
    public HandleTemp(TModel model) { _model = model;}

    public bool With<TCommandHandler>() where TCommandHandler : ICommandHandler<TModel> {
    }
}

So I'm now calling it like:

Handle(model).With<MyCommandHandler>();

Are there other possibilities? Did I make something completely wrong with my solution?

Shaddix
  • 5,901
  • 8
  • 45
  • 86

2 Answers2

4

No, your analysis and solution look about right. Indeed, generic type inference can work only on an all-or-nothing basis. If there are some generic parameters that can't be inferred, all must be explicitly stated. Personally I'd quite like a way to say "you worry about these parameters, I'll tell you this one", but... that doesn't exist.

The only other option is to add an artificial extra regular parameter to allow it to infer the generic parameter - a bit yucky.

One other option: challenge the assumption that generics are needed here. For example, could it just be a Type instance? Would:

bool Handle<TModel>(TModel model, Type type)...
...
Handle(model, typeof(MyCommandHandler));

work, for example? I can't answer this directly, as I don't know the particulars of your _container.Resolve<TCommandHandler>(); method, as to whether that could be adjusted to take a Type rather than a <T>.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    Yep, that could be easily converted to argument of `Type`, but I'd like to have a compile-time checking (that generic-types offer) to make it impossible to pass in a `Type` that doesn't implement my ICommandHandler. Thanks for reviewing my implementation :) – Shaddix Oct 04 '11 at 07:49
  • See also Eric Lippert's answer to a question about [Mumble Typing](http://stackoverflow.com/questions/5693503/what-is-mumble-typing/5693505#5693505). – Brian Oct 07 '11 at 13:34
1

All the C# compiler needs is a demonstration of the type in the arguments, so instead of attempting to place it in the generic arguments (at the usage site) make something that lets you provide an argument that helps the compiler identify that type. To make it less confusing, here is an example:

// Your classes/interfaces.
class Container
{
    public static T Resolve<T>()
    {
        Console.WriteLine("Resolving {0}", typeof(T).FullName);
        return default(T);
    }
}
interface ICommandHandler<TModel>
{
    void DoSomething();
}

// An implemented ICommandHandler.
public class WackyCommandHandler : ICommandHandler<string>
{
    public void DoSomething() { }
}

// Used to help the C# compiler identify types.
public static class Identify
{
    public static TypeIdentity<TType> TheType<TType>()
    {
        return null; // You don't actually need an instance.
    }
}
public sealed class TypeIdentity<TType>
{
    private TypeIdentity() { }
}

// Your method
static bool Handle<TCommandHandler, TModel>(TModel model, TypeIdentity<TCommandHandler> handler)
    where TCommandHandler : ICommandHandler<TModel>
{
    var item = Container.Resolve<TCommandHandler>();
    return true;
}

// And the usage site:
var a = "hello";
Handle(a, Identify.TheType<WackyCommandHandler>());
Console.ReadLine();
Jonathan Dickinson
  • 9,050
  • 1
  • 37
  • 60
  • 1
    thanks, I got your point, but it looks for me that my implementation will be clearer to me when I'll use it :) – Shaddix Oct 06 '11 at 17:26