3

I have the following method where T is used inside a Func:

public void DoSomething<T>(string someString, Func<T, bool> someMethod) 
{    
    if(someCondition) 
    {
        string A;
        bool resultA = someMethod(A);
    }
    else 
    {
        string[] B;
        bool resultB = someMethod(B);
    }    
    // Some other stuff here ...
}

I am invoking the DoSomething method in the following manner:

DoSomething<string>("abc", someMethod);
DoSomething<string[]>("abc", someMethod);

And the someMethod exists with the following definitions:

bool someMethod(string simpleString);
bool someMethod(string[] stringArray);

Now the compilation fails with the following errors in method DoSomething:

cannot convert from 'string' to 'T'
cannot convert from 'string[]' to 'T'

I am unable to figure out if there is a solution to the problem, or what I am trying is not feasible. It looks similar to question How can I pass in a func with a generic type parameter?, though it was not helpful for my scenario.

sanchitkum
  • 333
  • 2
  • 6
  • 18
  • Did you mean to use `someMethod()` inside `DoSomething()` at all? Perhaps instead of `method()`...? – John Wu Jul 16 '18 at 15:32
  • @JohnWu My bad, I have updated the snippet to use `someMethod()`. ~Thanks – sanchitkum Jul 16 '18 at 16:09
  • Technically it is feasible to do what you're trying to do; if under certain conditions you know that `T` is `string` then you could cast `someMethod` to `Func` and invoke that specific function rather than `someMethod` directly. But just because you *can* do this doesn't mean that you *should*. Casting your generic arguments to specific types under specific conditions rather defeats the purpose of using a generic method in the first place. John Wu's answer looks like a *much* better design than what you're trying to do. If you can't use it, could you please explain why? – Joe Farrell Jul 16 '18 at 16:34

2 Answers2

5

Your example seems a little inconsistent, but if you were writing things generically, it should look more like this:

public void DoSomething<T>(string someString, Func<T, bool> someMethod) 
{
    T a;
    someMethod(a);
}

Notice that instead of using if to choose between types, and then declaring the type as either a string or string[], we simply declare the type as T, which will get substituted when the code is compiled so that it will be appropriate for the function.

The moment you find yourself picking between types using if or switch case, you probably don't want a generic solution; the logic isn't, in fact, generic at all. It is specific. In that sort of case, just write two prototypes:

public void DoSomething(string someString, Func<string, bool> someMethod) 
{    
    string A;
    bool resultA = someMethod(A);
}


public void DoSomething(string someString, Func<string[], bool> someMethod) 
{    
    string[] A;
    bool resultA = someMethod(A);
}

This is known as method overloading. The compiler will automatically pick the right method with the right arguments by inferring the types from the supplied function.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • Thank You @JohnWu, I agree method overloading would be a neat solution, but in the actual context (not detailed here) it would mean code duplication (as the method is somewhat hard to refactor or break). I should have been more specific and mentioned why method overloading wasn't considered for this scenario. In any case, I was looking if the above is feasible somehow. ~Thanks. – sanchitkum Jul 16 '18 at 16:18
  • 1
    @sanchitkum, if there is some context that would explain why you can't go with an overloading solution, then I'd recommend updating your question to include it. Failing that, John's answer is probably the best one you're going to get. – Joe Farrell Jul 16 '18 at 16:30
0

You can achieve it via reflection:

public void DoSomething<T>(string someString, Func<T, bool> someMethod)
{
    var args = new Dictionary<Type, object>
    {
        [typeof(string)] = "string", //string A;
        [typeof(string[])] = new[] { "string" }, //string[] B;
    };
    var arg = args[typeof(T)];
    var result = (bool)someMethod.Method.Invoke(someMethod.Target, new[] { arg });
}

Usage:

DoSomething<string>("abc", someMethod);
DoSomething<string[]>("abc", someMethod);
Slava Utesinov
  • 13,410
  • 2
  • 19
  • 26