2

I've got a generic command defenition with a single argument that returns some value

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

And I've got an interpreter with a generic method for that commands type

class Interpreter{
  public TResult Run<TCommand, TArg, TResult>(TArg arg) 
      where TCommand: ICommand<TArg, TResult>, new()
  {
      var cmd = new TCommand();
      return cmd.Run(arg);
  }

So i call these commands in a way like that

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

where

ConvertCommand: ICommand<string, double>

But i want to launch these commands in a minimalistic way

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

It seems that there enough generic type information for CLR for compiling that but it doesn't want to.

Is there any way to launch this type of generic methods with a single generic argument?

Leo Shine
  • 23
  • 5
tmt
  • 686
  • 2
  • 10
  • 22

1 Answers1

1

Well, generic type inference requires that method arguments provide the type for the arguments to let the compiler infer their generic types.

So only TArg could be infered, while TResult not. In summary: no, you can't call a generic method without providing all generic arguments.

Possible alternative: refactor your code as follows...

I believe that I can give you a draft of what I would consider a better design in your case. Check the code and later I explain it bellow the sample:

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

I think that you shouldn't delegate the responsibility of building commands to the interpreter, but it should be a command factory. That is, the interpreter just run the command, gets command results, processes them, emits events... this is now up to you.

In the other hand, check that Interpreter.Run method receives an ICommand<TArg, TReturn> instead of a generic type parameter. This way, **both TArg and TReturn generic type arguments can be inferred from the ICommand<TArg, TReturn> from its implementation and you don't need to provide these generic arguments explicitly:

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

Actually I would go with other designs/architectures in a real-world scenario, but I wanted to give you a hint on how to refactor your actual idea and let it work as you expect ;)

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • but i've got this information in IComand defenition. There is no way to use it? – tmt Jan 26 '16 at 18:26
  • 1
    @tmt No. [You can't partially infer generic arguments](http://stackoverflow.com/a/8511493/1081897). You can have the compiler infer all or none of them. – D Stanley Jan 26 '16 at 18:42
  • Sure, Thx. This is what i've tried to avoid. instead of dirty 3-line construction with using, dirty creation synthax (new(), or, factory ). But life is imperfect. Almost as C#... – tmt Jan 26 '16 at 20:16
  • @tmt Well, C# is a strongly-typed language. If you can't guarantee typing during compile-time, C# can't guess what's in your mind. I believe that it's one of the most powerful language available today and it has an impressive feature set. IMHO, there're few cases where C# is the limitation: most of the times it's more about our mind: we've a toolset and we need to build software based on the tool. Sometimes imagination goes beyond of what's ever possible :D – Matías Fidemraizer Jan 27 '16 at 08:32
  • @MatíasFidemraizer Yes, # is the best. That example,contains full information types. As you need no to specify generic arguments in linq calling (where "specifying" object is argument) - also there are full information about types, but in calling generic first argument type. I see - there are no language constructions in c# that allow us to call some generics in a short way, if all generic arguments are related, but in theory it seems possible. Am i missed something? – tmt Jan 28 '16 at 15:42
  • @tmt It's harder than you imagine... Some human assumptions are hard to implement and cover every case without allowing dangerous programming practices... – Matías Fidemraizer Jan 28 '16 at 15:53