Use Action or FUNC in dictionaries - c#

i was wondering if it is possible to pass a template into a function like this example:
Dictionary<string, Action<object>> myDict= new Dictionary<string, Action<object>>();
myDict.Add("someString",(nameOfMethod));
this method for example is a setter so it receives as a parameter (double or string or int etc...) and return void.
i suppose the following is impossible..
(i got this ERROR : Error The best overloaded method match for 'System.Collections.Generic.Dictionary>.Add(string, System.Action)' has some invalid arguments)
any ideas how to do it?

this method for example is a setter so it receives as a parameter (double or string or int etc...) and return void.
That's the problem - a method accepting a double isn't applicable for Action<object>, because an Action<object> should be able to be invoked with any object reference as the argument.
You can use a lambda expression to cast and convert though:
myDict.Add("somestring", o => MethodAcceptingDouble((double) o));
You could even write a helper method to do it, although unfortunately due to limitations of type inference you need to specify the type argument explicitly.
static class Test
{
static void Main()
{
var dictionary = new Dictionary<string, Action<object>>();
AddAction<double>(dictionary, "somestring", SampleMethod);
}
static void AddAction<T>(Dictionary<string, Action<object>> dictionary,
string name,
Action<T> action)
{
dictionary.Add(name, arg => action((T) arg));
}
static void SampleMethod(double input)
{
}
}

Related

Force C# compiler to use non-generic method overload with Linq Expression parameter

I have overloaded methods, one generic and one non-generic. The two methods both receive a Linq Expression as single parameter:
public void Test(Expression<Action<char>> expr) {}
public void Test<T>(Expression<Func<char, T>> expr) {}
Now consider the following invocation:
var sb = new StringBuilder();
Test(c => sb.Append(c));
The compiler will pick the generic method since the Append() method does (unfortunately) return a StringBuilder. However, in my case I absolutely need the non-generic method to be called.
The following workaround shows that there is no type issue with the code (the non-generic call would be perfectly valid):
Expression<Action<char>> expr = c => sb.Append(c);
Test(expr);
However, I'd prefer not to declare a variable with an explicit type and instead somehow get the compiler to pick the non-generic method (just like I could tell it to use the generic method with explicit type parameters).
You can play with this at SharpLab.io.
This may seem like a workaround (because it is), but you can used a named parameter to clarify which method you are calling.
static public void Test(Expression<Action<char>> action)
{
Console.WriteLine("Test()");
}
static public void Test<T>(Expression<Func<char, T>> func)
{
Console.WriteLine("Test<T>()");
}
When you want the non-generic version, just provide the parameter name action: in the argument list.
static public void Main()
{
var sb = new StringBuilder();
Test(action: c => sb.Append(c) );
Test(func: c => sb.Append(c) );
}
Output:
Test()
Test<T>()
This might be easier to use than writing out the expression cast.
Fiddle
You can use an empty method to swallow the return value of sb.Append. I wouldn't call this a workaround, since it just makes the compiler work normally, but it isn't totally clean and pretty either.
static public void NoValue(object value) {}
static public void Test(Expression<Action<char>> action)
{
Console.WriteLine("Test()");
}
static public void Test<T>(Expression<Func<char, T>> func)
{
Console.WriteLine("Test<T>()");
}
When you wrap the output in NoValue, the compiler correctly sees this as an Action, not a function.
static public void Main()
{
var sb = new StringBuilder();
Test(c => NoValue(sb.Append(c)) );
Test(c => sb.Append(c) );
}
Output:
Test()
Test<T>()

Use generic type parameter in a Func, and invoke Func with specific type?

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

Don't understand compile error for method call with lambda expression

I have used this question to "pass a property as a parameter to a method" and change the property's value with an additional parameter. My problem is not how to accomplish that but rather the method call results in a compile error.
Call and method definition
Run(f => f.A, 15);
public static void Run<T, TValue>(Expression<Func<T, TValue>> lamdaExpression, TValue value)
I get this error:
Error CS0411: The type arguments for method Program.Run<T, TValue>(Expression<Func<T, TValue>>, TValue) cannot be inferred from
the usage. Try specifying the type arguments explicitly
I have already searched on the above message and there are several examples, none are like mine. So I don't understand what is the problem.
Please help!
Additional information
I have one similar method call and method definition which don't have this problem. So I'm a bit confused.
Run(foo, f => f.A, 10);
public static void Run<T, TValue>(T obj, Expression<Func<T, TValue>> property, TValue value)
Notice this method has the same Expression<Func<T, TValue>> property and its working.
The program I've been using:
class Foo
{
public int A {get; set; }
}
class Program
{
public static void Main()
{
var foo = new Foo();
//... Calls to the methods...
}
}
The problem is that f => f.A cannot be used to infer the type of f.
So, easy fix:
Run<Foo, int>(f => f.A, 15);
Notice that if you have to specify one of the type arguments, you need to specify all of them.
Your other method works because T is inferred from the first parameter T obj

Mixing Reflection with Standard Calls

Let me preface this by saying that I am completely new to reflection.
I have a Dictionary of string to Func<string, string>. I'd like to add a configuration section that would allow me to define the name of static methods that can be programmatically added into this dictionary.
So basically, I'd have something like this:
public static void DoSomething()
{
string MethodName = "Namespace.Class.StaticMethodName";
// Somehow convert MethodName into a Func<string, string> object that can be
// passed into the line below
MyDictionary["blah"] = MethodNameConvertedToAFuncObject;
MyDictionary["foo"] = ANonReflectiveMethod;
foreach(KeyValuePair<string, Func<string, string>> item in MyDictionary)
{
// Calling method, regardless if it was added via reflection, or not
Console.WriteLine(item.Value(blah));
}
}
public static string ANonReflectiveMethod(string AString)
{
return AString;
}
Is it possible to do this, or do I need everything invoked through reflection?
I think all you're looking for is Delegate.CreateDelegate. You'll need to break the name you've got into a class name and a method name. You can then use Type.GetType() to get the type, then Type.GetMethod() to get the MethodInfo, then use:
var func = (Func<string, string>) Delegate.CreateDelegate(
typeof(Func<string, string>), methodInfo);
Once you've created the delegate, you can put it into the dictionary with no problems.
So something like:
static Func<string, string> CreateFunction(string typeAndMethod)
{
// TODO: *Lots* of validation
int lastDot = typeAndMethod.LastIndexOf('.');
string typeName = typeAndMethod.Substring(0, lastDot);
string methodName = typeAndMethod.Substring(lastDot + 1);
Type type = Type.GetType(typeName);
MethodInfo method = type.GetMethod(methodName, new[] { typeof(string) });
return (Func<string, string>) Delegate.CreateDelegate(
typeof(Func<string, string>), method);
}
Note that Type.GetType() will only find types in the currently executing assembly or mscorlib unless you actually specify an assembly-qualified name. Just something to consider. You might want to use Assembly.GetType() instead if you already know the assembly you'll be finding the method in.

Get "Object" return type from Func<MyClass, object>

Let's suppose I have defined Func as follows:
Func<MyClass, object> f = o => o.StringProperty;
or
Func<MyClass, object> f = o => o.Property.SomeMethod();
Is there way to get the actual return type without specifically calling it?
You can get the return type like this:
f.Method.ReturnType
But this will return you the type object. If you want to get Method or String or something that derives from object, you won't be able to have the information unless you call the method.
Actually you could, but this would mean that you'd have to dissassemble the method core and then analyze it to see what the method can return. But even then, there might be many different return types.
So the answer is: if you want to know that it returns an object, then yes you can, otherwise it's not worth the trouble, and it's better to find another way of doing what you need.
Since you are retrieving these Func<MyClass, object> delegates at runtime from other sources, the type information is essentially lost.
Instead, where these functions are defined, you can have the callers essentially encode that type information in a wrapped delegate by taking advantage of the LINQ Expression API (EDIT: Silly me, far more simpler at this point; we already have the generic compile time information):
public class MyClassDelegate
{
private readonly Func<MyClass, object> Function;
public Type ReturnType { get; private set; }
private MyClassDelegate(Func<MyClass, object> function, Type returnType)
{
this.Function = function;
this.ReturnType = returnType;
}
public object Invoke(MyClass context)
{
return Function(context);
}
public static MyClassDelegate Create<TReturnType>(Func<MyClass, TReturnType> function)
{
Func<MyClass, object> nonTypedFunction = o => function(o);
return new MyClassDelegate(nonTypedFunction, typeof(TReturnType));
}
}
(A derived generic MyClassDelegate<TReturnType> : MyClassDelegate class could be made as well to get around some of the sillyness in the Create method, or avoid value-type boxing, or to have the return type information available at compile time or even by reflecting on whatever MyClassDelegate<TReturnType> is.)
Callers defining the delegates instead of working directly with a Func<MyClass, object> would instead work with this class and define their delegates as:
MyClassDelegate f1 = MyClassDelegate.Create(o => o.StringProperty);
MyClassDelegate f2 = MyClassDelegate.Create(o => o.Property.SomeMethod());
Your API would require a MyClassDelegate, with which you can easily access their types:
Console.WriteLine(f1.ReturnType.FullName); //string
Console.WriteLine(f2.ReturnType.FullName); //whatever `SomeMethod()` is declared to return
Finally, you can invoke the delegates or even create Func<MyClass, object> delegates still:
f1.Invoke(myClassInstance);
Func<MyClass, object> f3 = f1.Invoke;
You can do something close to this by using a generic method to make the compiler infer the type arguments:
static Func<T1, R> Infer<T1, R>(Func<T1, R> f) { return f; }
And then:
var func = Infer((string s) => s.Length);
This will encode the return type into the type of func at compilation time.
Of course for a more generally applicable solution you would need a bunch of overloads of Infer to cover Action and Func with one, two, three, etc arguments.
If you then want to get the return type at runtime, for any kind of Func it's as simple as func.Method.ReturnType as ppetrov has already pointed out.

Categories