开发者

Syntax sugar for double-generic function

开发者 https://www.devze.com 2023-04-10 17:31 出处:网络
I have the following function in c#: bool Handle<TCommandHandler, TModel>(TModel model) where TCommandHandler : ICommandHandler<TModel> {

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 Handl开发者_Python百科eTemp(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?


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>.


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();
0

精彩评论

暂无评论...
验证码 换一张
取 消