通用参数在方法中自动定义

时间:2016-01-26 18:03:06

标签: c# .net generics

我有一个通用命令defenition,其中一个参数返回一些值

interface ICommand<Targ, TResult> {
    TResult Run(Targ argument);    
}

我有一个带有命令类型

的通用方法的解释器
class Interpreter{
  public TResult Run<TCommand, TArg, TResult>(TArg arg) 
      where TCommand: ICommand<TArg, TResult>, new()
  {
      var cmd = new TCommand();
      return cmd.Run(arg);
  }

所以我以这样的方式调用这些命令

var interpreter = new Interpreter();
double converted = interpreter.Run<ConvertCommand, string, double>("123.5");

其中

ConvertCommand: ICommand<string, double>

但我想以简约的方式启动这些命令

var interpreter = new Interpreter();
double converted = interpreter.Run<ConvertCommand>("123.5");

似乎CLR有足够的通用类型信息来编译,但它不想。

有没有办法用一个通用参数启动这种类型的泛型方法?

1 个答案:

答案 0 :(得分:1)

那么,泛型类型推断要求方法参数提供参数的类型,以便让编译器推断它们的泛型类型。

因此只有TArg可能被感染,而TResult则不然。 总结:不,您不能在不提供所有通用参数的情况下调用泛型方法。

可能的替代方法:重构您的代码,如下所示......

我相信我可以为您提供一份草案,说明我认为更适合您的设计。检查代码,稍后我会在示例中解释它:

public interface ICommand<TArg, TResult>
{
    TArg Arg { get; set; }
    TResult Run();
}

public sealed class ConvertCommand : ICommand<string, double>
{
    public string Arg { get; set; }

    public double Run()
    {
        return Convert.ToDouble(Arg);
    }
}

public static class CommandFactory
{
    public static TCommand Create<TCommand, TArg, TReturnValue>(TArg arg)
        where TCommand : ICommand<TArg, TReturnValue>, new ()
    {
        var cmd = new TCommand();
        cmd.Arg = arg;
        return cmd;
    }

    // This is like a shortcut method/helper to avoid providing 
    // generic parameters that can't be inferred...
    public static ConvertCommand ConvertCommand(string arg)
    {
        return Create<ConvertCommand, string, double>(arg);
    }
}

class Interpreter
{
    public TReturnValue Run<TArg, TReturnValue>(ICommand<TArg, TReturnValue> cmd)
    {
        return cmd.Run();
    }
}

我认为您不应该将构建命令的责任委托给解释器,但它应该是命令工厂。也就是说,解释器只运行命令,获取命令结果,处理它们,发出事件......这取决于你。

另一方面,检查Interpreter.Run方法是否收到ICommand<TArg, TReturn>而不是泛型类型参数。这样,** TArgTReturn泛型类型参数都可以从ICommand<TArg, TReturn>的实现中推断出来,并且您不需要明确提供这些通用参数:

Interpreter interpreter = new Interpreter();
// TArg and TReturn are inferred!!
interpreter.Run(CommandFactory.ConvertCommand("0.1"));

实际上我会在实际场景中使用其他设计/架构,但我想给你一个关于如何重构你的实际想法并让它按预期工作的提示;)