Синтаксис сахара для двойной универсальной функции - PullRequest
6 голосов
/ 04 октября 2011

У меня есть следующая функция в c #:

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

Так как TModel ясно из параметра функции, я хочу каким-то образом не указывать ее тип при вызове функции. В идеале я хочу назвать это как:

Handle<MyCommandHandler>(model);

Поскольку это, вероятно, невозможно, я придумал следующее:

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> {
    }
}

Так что я сейчас называю это как:

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

Есть ли другие возможности? Что-то не так с моим решением?

Ответы [ 2 ]

4 голосов
/ 04 октября 2011

Нет, ваш анализ и решение выглядят правильно. Действительно, вывод обобщенного типа может работать только на основе «все или ничего». Если есть некоторые общие параметры, которые не могут быть выведены, все должны быть явно указаны. Лично я бы очень хотел сказать: «Вы беспокоитесь об этих параметрах, я расскажу вам об этом», но ... этого не существует.

Единственный другой вариант - добавить искусственный дополнительный обычный параметр, чтобы он мог выводить универсальный параметр - немного противный.

Еще один вариант: опровергнуть предположение, что здесь нужны дженерики. Например, это может быть просто экземпляр Type? Будет:

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

работа, например? Я не могу ответить на этот вопрос напрямую, так как я не знаю подробностей вашего _container.Resolve<TCommandHandler>(); метода, относительно того, можно ли , что быть скорректирован, чтобы принять Type вместо <T>.

1 голос
/ 04 октября 2011

Все, что нужно компилятору C #, - это демонстрация типа в аргументах, поэтому вместо того, чтобы пытаться поместить его в универсальные аргументы (на сайте использования), создайте что-то, что позволит вам предоставить аргумент, который поможет компилятору идентифицировать этот тип,Чтобы сделать его менее запутанным, вот пример:

// 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...