Calling a function from a string in C# - c#

I know in php you are able to make a call like:
$function_name = 'hello';
$function_name();
function hello() { echo 'hello'; }
Is this possible in .Net?

Yes. You can use reflection. Something like this:
Type thisType = this.GetType();
MethodInfo theMethod = thisType.GetMethod(TheCommandString);
theMethod.Invoke(this, userParameters);
With the above code, the method which is invoked must have access modifier public. If calling a non-public method, one needs to use the BindingFlags parameter, e.g. BindingFlags.NonPublic | BindingFlags.Instance:
Type thisType = this.GetType();
MethodInfo theMethod = thisType
.GetMethod(TheCommandString, BindingFlags.NonPublic | BindingFlags.Instance);
theMethod.Invoke(this, userParameters);

You can invoke methods of a class instance using reflection, doing a dynamic method invocation:
Suppose that you have a method called hello in a the actual instance (this):
string methodName = "hello";
//Get the method information using the method info class
MethodInfo mi = this.GetType().GetMethod(methodName);
//Invoke the method
// (null- no parameter for the method call
// or you can pass the array of parameters...)
mi.Invoke(this, null);

class Program
{
static void Main(string[] args)
{
Type type = typeof(MyReflectionClass);
MethodInfo method = type.GetMethod("MyMethod");
MyReflectionClass c = new MyReflectionClass();
string result = (string)method.Invoke(c, null);
Console.WriteLine(result);
}
}
public class MyReflectionClass
{
public string MyMethod()
{
return DateTime.Now.ToString();
}
}

This code works in my console .Net application
class Program
{
static void Main(string[] args)
{
string method = args[0]; // get name method
CallMethod(method);
}
public static void CallMethod(string method)
{
try
{
Type type = typeof(Program);
MethodInfo methodInfo = type.GetMethod(method);
methodInfo.Invoke(method, null);
}
catch(Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
Console.ReadKey();
}
}
public static void Hello()
{
string a = "hello world!";
Console.WriteLine(a);
Console.ReadKey();
}
}

A slight tangent -- if you want to parse and evaluate an entire expression string which contains (nested!) functions, consider NCalc (http://ncalc.codeplex.com/ and nuget)
Ex. slightly modified from the project documentation:
// the expression to evaluate, e.g. from user input (like a calculator program, hint hint college students)
var exprStr = "10 + MyFunction(3, 6)";
Expression e = new Expression(exprString);
// tell it how to handle your custom function
e.EvaluateFunction += delegate(string name, FunctionArgs args) {
if (name == "MyFunction")
args.Result = (int)args.Parameters[0].Evaluate() + (int)args.Parameters[1].Evaluate();
};
// confirm it worked
Debug.Assert(19 == e.Evaluate());
And within the EvaluateFunction delegate you would call your existing function.

Related

C# Create lambda over given method that injects first paramater

In C# I have following methods defined in given class (non static):
int MyMethod(ScriptEngine script, int a, int b) {
return a + b;
}
void MyMethod2(ScriptEngine script, string c) {
// do something with c
}
I want to create wrapping lambda / Action / Delegate / MethodInfo (all are accepted by script engine) that automatically passes ScriptEngine and this from given, predefined variables.
So far I've experimenting with:
// With overloads up to 16 template parameters
Action<T1> Wrap<T1>(Action<ScriptEngine, T1> func, ScriptEngine script) {
return (Action<T1>) ((t1) => func(script, t1));
}
But when called on MyMethod2 I've got The type arguments for method … cannot be inferred from the usage. Try specifying the type arguments explicitly. If I specify the template arguments explicity, it works, but I want to avoid such specification.
Is there any other way (not neccesery following my solution) I can create such wrapper automatically (or semi-automatically)?
It is worth mentioning that there is a dedicated abstract method void RegisterAll(ScriptEngine script) that can register required members of given subclass.
Here is an example of what I am trying to achieve:
class ScriptEngine { // Stub to have complete example, actual implementation is defined elsewhere
void RegisterApi(string name, MethodInfo methodInfo) { }
void RegisterApi(string name, Delegate delegateSelf) { }
}
class Api {
int MyMethod(ScriptEngine script, int a, int b) {
return a + b;
}
void MyMethod2(ScriptEngine script, string c) {
// do something with c
}
void RegisterAll(ScriptEngine script) {
// Is there any way to shorten this up (not providing MyMethod twice, not providing template arguments?)
script.RegisterApi(nameof(MyMethod), (Delegate)Wrap<string>(MyMethod, script));
}
}
The problem is how to improve this RegisterApi method so it:
Takes the method only once
Does not require specifying arguments via template method
There is actually another solution that does not involve emiting new Expressions (could fail on iOS!)
First, let us define following wrapper:
private class Wrapper
{
public readonly object container;
public readonly MethodInfo method;
public readonly ScriptEngine engine;
public Wrapper(object container, MethodInfo method, ScriptEngine engine)
{
this.container = container;
this.method = method;
this.engine = engine;
}
public Action CreateAction()
{
return () => method.Invoke(container, new object[] { engine });
}
public Action<T1> CreateAction<T1>()
{
return (arg1) => method.Invoke(container, new object[] { engine, arg1 });
}
// etc
}
Now you can register method like that:
var type = typeof(Wrapper);
var instance = Activator.CreateInstance(type, new object[] { container, methodInfo, engine });
MethodInfo methodActual = null;
if (methodInfo.ReturnType == typeof(void))
{
var methods = type.GetMethods().Where(x => x.Name == "CreateAction");
foreach (var method in methods)
{
if (method.GetGenericArguments().Length == methodInfo.GetParameters().Length - 1)
{
methodActual = method.MakeGenericMethod(methodInfo.GetParameters().Skip(1).Select(x => x.ParameterType).ToArray());
}
}
}
var actionToRegister = methodActual.Invoke(instance, new object[0]);
The solution is to use Expression Tree to create a simple delegate wrapper.
var parameterEngine = Expression.Constant(script, typeof(ScriptEngine));
var parameterCaller = Expression.Constant(this, this.GetType());
// Build parameters, skipping the first. Note that trailing "ToList" is important!
var parameters = methodInfo.GetParameters().Skip(1).Select(x => Expression.Parameter(x.ParameterType, x.Name)).ToList();
// Inject parameter
var mergedParameters = new List<Expression>();
mergedParameters.Add(parameterEngine);
mergedParameters.AddRange(parameters);
// Bind together
var call = Expression.Call(parameterCaller, methodInfo, mergedParameters);
var expression = Expression.Lambda(call, parameters);
var method = expression.Compile();
// Method can now be registered

How to Invoke Method<T>(Func<Action<T>> action) with private type

I hope the code snipped illustrates my issue.
I need to Invoke the CallEvent method like it is in the out-commented line.
I have no access to the ThirdParty or AnotherThirdParty class.
This is as far as I come:
public class ThirdParty
{
private struct MsgType
{ }
private static void AnotherFunc(MsgType msg)
{ }
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{ }
}
public class MyClass
{
public static void Main()
{
Type MsgType = typeof(ThirdParty).GetNestedType(
"MsgType", BindingFlags.Instance | BindingFlags.NonPublic);
object msg = Activator.CreateInstance(MsgType);
MethodInfo CallEvent = typeof(AnotherThirdParty).GetMethod("CallEvent");
CallEvent = CallEvent.MakeGenericMethod(MsgType);
MethodInfo AnotherFunc = typeof(ThirdParty).GetMethod(
"AnotherFunc", BindingFlags.Static | BindingFlags.NonPublic);
CallEvent.Invoke(null, new object[] {???, msg});
//CallEvent<MsgType>((int x) => new Action<MsgType>(AnotherFunc), msg);
// I can't get my head around how to solve this (Action<msgtype>)
}
}
I also tried:
CallEvent.Invoke(null, new object[]
{
new Func<int, Action<object>>((int x) =>
new Action<object>((object y) =>
AnotherFunc.Invoke(null, new object[] { y }))),
msg
});
I get the following Exception:
System.ArgumentException: Object of type
'System.Func2[System.Int32,System.Action1[System.Object]]' cannot be
converted to type
'System.Func2[System.Int32,System.Action1[ThirdParty+MsgType]].
How should I proceed?
public class ThirdParty
{
private struct MsgType { }
private static void AnotherFunc(MsgType msg)
{
// Inserted to demonstrate getting here
Console.WriteLine($"HEY: {msg}");
}
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{
// Inserted to demonstrate calling the func and then
// the action
action(12)(arg);
}
}
public static void Main()
{
var msgTypeType =
typeof(ThirdParty).GetNestedType("MsgType", BindingFlags.NonPublic);
// This is the message type we're passing (presumably you'll do more with it)
var ourMsgTypeArg = Activator.CreateInstance(msgTypeType);
// Get the reference to the CallEvent method
var callEventMethod =
typeof(AnotherThirdParty).GetMethod("CallEvent", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(msgTypeType);
// Get the reference to the AnotherFunc method
var anotherFunc =
typeof(ThirdParty).GetMethod("AnotherFunc", BindingFlags.NonPublic | BindingFlags.Static);
// Build the func to pass along to CallEvent
var func = CreateFunc(msgTypeType, anotherFunc);
// Call the CallEvent<MsgType> method.
callEventMethod.Invoke(null, new object[] {
func,
ourMsgTypeArg
});
}
private static Delegate CreateFunc(Type msgType, MethodInfo anotherFunc)
{
// The func takes an int
var intArg = Expression.Parameter(typeof(int));
// The action takes a msgType
var msgTypeArg = Expression.Parameter(msgType);
// Represent the call out to "AnotherFunc"
var call = Expression.Call(null, anotherFunc, msgTypeArg);
// Build the action to just make the call to "AnotherFunc"
var action = Expression.Lambda(call, msgTypeArg);
// Build the func to just return the action
var func = Expression.Lambda(action, intArg);
// Compile the chain and send it out
return func.Compile();
}
This code functions as you've requested and prints the following:
HEY: UserQuery+ThirdParty+MsgType
This seems to run:
MethodInfo miCreateDelegate = typeof(MethodInfo).GetMethod("CreateDelegate", new[] { typeof(Type), typeof(Object) });
var ActionType = typeof(Action<>).MakeGenericType(MsgType);
var lambdabody = Expression.Convert(Expression.Call(Expression.Constant(AnotherFunc), miCreateDelegate, new[] { Expression.Constant(ActionType), Expression.Constant(null) }), ActionType);
var intparm = Expression.Parameter(typeof(int));
var lambda = Expression.Lambda(lambdabody, intparm);
CallEvent.Invoke(null, new object[] {
lambda.Compile(),
msg
});
A more complete answer is how did I generate this? I used LINQPad to compile a simpler, similar expression substituting string for MsgType into an Expression:
public static void afunc(string x) { }
Expression<Func<int, Action<string>>> lambda = (int x) => new Action<string>(afunc);
Then I used the LINQPad Dump() function to output the expression tree.
lambda.Dump();
Then some spelunking in MSDN Expression documentation gave me the right static methods to create the pieces. I already knew how to instantiate generic types from an extension method for LINQPad that creates anonymous types on the fly to extend Dump() to exclude fields from anonymous objects, and I knew how to create lambdas from an extension method that extends LINQ with a proper SQL-translatable Left and Right Join operation.
Use Delegate.CreateDelegate method to construct an Action<MsgType> object. Construct Func<int,Action<T>> using Expression.Lambda<>:
var actionType = typeof(Action<>).MakeGenericType(MsgType);
var funcType = typeof(Func<,>).MakeGenericType(typeof(int), actionType);
var p1 = Expression.Parameter(typeof(int));
var p2 = Expression.Parameter(actionType);
var delegate = Expression.Constant(Delegate.CreateDelegate(actionType, AnotherFunc), funcType);
var lambda = Expression.Lambda(delegate, p1, p2);
CallEvent.Invoke(null, new object[] {
lambda.Compile()
, msg
});
This will work and will print an A but the function factory is a mistery to me so I just returned the created delegate. And this is compatible with .net standard 1.1
static void Main(string[] args)
{
Type MsgType = typeof(ThirdParty).GetNestedType(
"MsgType", BindingFlags.Instance | BindingFlags.NonPublic);
object msg = Activator.CreateInstance(MsgType);
MethodInfo CallEvent = typeof(AnotherThirdParty).GetMethod("CallEvent");
CallEvent = CallEvent.MakeGenericMethod(MsgType);
MethodInfo AnotherFunc = typeof(ThirdParty).GetMethod(
"AnotherFunc", BindingFlags.Static | BindingFlags.NonPublic);
var actionType = typeof(Action<>).MakeGenericType(MsgType);
var actionDelegate = AnotherFunc.CreateDelegate(actionType);
var param = Expression.Parameter(typeof(int));
var funcDelegate = Expression.Lambda(Expression.Constant(actionDelegate),param).Compile();
CallEvent.Invoke(null, new []{ funcDelegate, msg });
Console.ReadLine();
}
public class ThirdParty
{
private struct MsgType
{ }
private static void AnotherFunc(MsgType msg)
{
Console.WriteLine("A");
}
}
public class AnotherThirdParty
{
public static void CallEvent<T>(Func<int, Action<T>> action, T arg)
{
action(1)(arg);
}
}

Understanding/Getting symbol type?

public void SomeMethod(string sampleString)
{ var helloworld = sampleString; }
Is it possible to determine if a particular symbol is a local variable, class field or method's parameter? e.g. if I call a FindSymbolAtPosition on the sampleString, will i be able to tell that the sampleString symbol is a method's parameter or variable?
EDIT: the requirement is that it must work from coding-time, for my static code analysis tool that im building with roslyn
You can't get it directly via properties, because in var helloworld = sampleString;, the statement has no context that if sampleString is a parameter or not. But you can get it from the method's context like this:
static bool IsParameter(IdentifierNameSyntax name)
{
SyntaxNode node = name;
while (node != null && !(node is MethodDeclarationSyntax))
{
node = node.Parent;
}
var method = node as MethodDeclarationSyntax;
if (method != null)
{
return method
.ParameterList
.Parameters
.Any(p => p.Identifier.Text.Equals(name.Identifier.Text));
}
return false;
}
Using .Parent to get the method context of the variable, and check if any parameter in .ParameterList matches the identifier.
UPDATE Code to prove it's working:
SyntaxTree tree = CSharpSyntaxTree.ParseText(
#"using System;
using System.Collections;
using System.Linq;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string i)
{
var j = ""1"";
var k = i + j;
}
}
}");
var root = (CompilationUnitSyntax)tree.GetRoot();
var ns = root.Members[0] as NamespaceDeclarationSyntax;
var cls = ns.Members[0] as ClassDeclarationSyntax;
var method = cls.Members[0] as MethodDeclarationSyntax;
var statement = method.Body.Statements[1] as LocalDeclarationStatementSyntax;
var variable = statement.Declaration.Variables[0];
var binary = variable.Initializer.Value as BinaryExpressionSyntax;
var vari = binary.Left as IdentifierNameSyntax;
var varj = binary.Right as IdentifierNameSyntax;
Console.WriteLine(IsParameter(vari)); //True
Console.WriteLine(IsParameter(varj)); //False
EDIT Base on #JeroenVannevel's comment, we can use SemanticModel.GetSymbolInfo.
var compilation = CSharpCompilation.Create("test", new[] { tree });
var semanticModel = compilation.GetSemanticModel(tree, true);
var symboli = semanticModel.GetSymbolInfo(vari);
var symbolj = semanticModel.GetSymbolInfo(varj);
//check symboli.Symbol.OriginalDefinition.Kind == SymbolKind.Parameter
Its wrong to compare identifiers by syntax or by text, imagine if the IdentifierNameSyntax is the name of MemberAccessExpressionSyntax and has the same identifier as a parameter, then you would incorrectly conclude that it is a parameter even though it is a member. You should work with the SemanticModel to determine what a SymbolKind is. You can use SemanticModel.GetDeclaredSymbol on declarations and SemanticModel.GetSymbolInfo().Symbol on symbol usages. Once you have the ISymbol it's easy to determine its kind. Bear in mind that different symbols have their own "sub-kinds", for instance ITypeSymbol has TypeKind property that determines if the type is Class, Struct, Interface, Array etc., so you should check them up.
You can use the following code to get the field information for class and parameters. Note, however, the detection of the method field is unavailable. This code uses reflection to query the assembly information and enumerates and compares the results.
static class Program
{
static void Main(string[] args)
{
SomeMethod("Hello, World!!!");
Type testType = typeof(Program);
FieldInfo[] fieldInfo = testType.GetFields();
MethodInfo methodInfo = testType.GetMethod("SomeMethod");
Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "sampleString"));
Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "classField"));
Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "helloWorld"));
Console.WriteLine("Parameter type:{0}", TypeOfField(fieldInfo, methodInfo, "nonexistentVariable"));
}
public static string classField = "Hello, World!!!";
public static void SomeMethod(string sampleString)
{
string helloWorld = sampleString;
}
public static string TypeOfField(FieldInfo[] fieldInfo, MethodInfo methodInfo, string fieldName)
{
if (IsClassField(fieldInfo, fieldName))
{
return "Class Field";
}
else if (IsParameter(methodInfo, fieldName))
{
return "Parameter";
}
else
{
return "Cannot determine";
}
}
private static bool IsClassField(FieldInfo[] fieldInfo, string classFieldName)
{
bool isClassField = false;
foreach (var item in fieldInfo)
{
if (item.Name == classFieldName)
{
isClassField = true;
break;
}
}
return isClassField;
}
private static bool IsParameter(MethodInfo methodInfo, string parameterName)
{
bool isParameter = false;
ParameterInfo[] paramInfo = methodInfo.GetParameters();
foreach (var item in paramInfo)
{
if (item.Name == parameterName)
{
isParameter = true;
break;
}
}
return isParameter;
}
}
You can distinguish whether you are dealing with a class field vs a method's parameter or a local variable with the keyword this. If you had a class field string called sampleString and you wanted to refer to the class field rather then the local variable/ method parameter then you would refer to it with this.sampleString. You would refer to the local variable/ method parameter as sampleString without the keyword (this). In terms of local variables and method parameters, you are not able to have a local variable and method parameter with the same name within the same method. With your code above you are referring to the sampleString parameter.

I want to get a method by reflection

I want to get a method by reflection,but the method has multiple overloads..and the method's parameters is a generic type..How can I do?
class Program
{
static void Main(string[] args)
{
test obj = new test();
Type[] types = { typeof(string) };
var method = obj.GetType().GetMethod("Say", BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);
method.Invoke(obj, new object[] { "hello world" });
Console.ReadKey();
}
}
public class test
{
private void Say(string value)
{
Console.WriteLine(value);
}
private void Say<T>(T t)
{
Console.WriteLine(t);
}
}
I can get private void Say(string value)..but I want to get private void Say<T>(T t)..
Type[] types = { typeof(string) }; Here how to set up here?
Based on the comments, I would rather go for a solution like:
public static MethodInfo GetGenericMethod(object obj, string methodName, Type genericParameter)
{
var method = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(m => m.Name.Equals(methodName) && m.IsGenericMethod);
return method.MakeGenericMethod(genericParameter);
}
And then call it with something like:
GetGenericMethod(obj, "Say", typeof(string));
You will then be able to invoke it like any other methods.
There are you ways.
Get all methods and find that one you're looking for
obj.GetType().GetMethods().Single(m=>m.GetParameters().Length = /* parameter count*/ && /* next condition */);
Use Expression tree
In my opinion is nicer and less error prone but can be used only when you known which method you want in compile time.
You need some helper method that extract Method for expression tree.
public static MethodInfo Method(Expression<Action> methodAccess)
{
return ((MethodCallExpression)methodAccess.Body).Method;
}
Then you can use it like this:
Get(()=>obj.Say<string>("My param")).GetGenericMethodDefinition();
Compiler will take care of selecting method and helper method will extract MethodInfo from expression tree. GetGenericMethodDefinition() call will give you open-generic version of selected method.

Invoking a method using reflection on a singleton object

So I have the following:
public class Singleton
{
private Singleton(){}
public static readonly Singleton instance = new Singleton();
public string DoSomething(){ ... }
public string DoSomethingElse(){ ... }
}
Using reflection how can I invoke the DoSomething Method?
Reason I ask is because I store the method names in XML and dynamically create the UI. For example I'm dynamically creating a button and telling it what method to call via reflection when the button is clicked. In some cases it would be DoSomething or in others it would be DoSomethingElse.
Untested, but should work...
string methodName = "DoSomething"; // e.g. read from XML
MethodInfo method = typeof(Singleton).GetMethod(methodName);
FieldInfo field = typeof(Singleton).GetField("instance",
BindingFlags.Static | BindingFlags.Public);
object instance = field.GetValue(null);
method.Invoke(instance, Type.EmptyTypes);
Great job. Thanks.
Here's the same approach with slight modification for cases that one can't have a reference to the remote assembly. We just need to know basic things such as the class fullname (i.e namespace.classname and the path to the remote assembly).
static void Main(string[] args)
{
Assembly asm = null;
string assemblyPath = #"C:\works\...\StaticMembers.dll"
string classFullname = "StaticMembers.MySingleton";
string doSomethingMethodName = "DoSomething";
string doSomethingElseMethodName = "DoSomethingElse";
asm = Assembly.LoadFrom(assemblyPath);
if (asm == null)
throw new FileNotFoundException();
Type[] types = asm.GetTypes();
Type theSingletonType = null;
foreach(Type ty in types)
{
if (ty.FullName.Equals(classFullname))
{
theSingletonType = ty;
break;
}
}
if (theSingletonType == null)
{
Console.WriteLine("Type was not found!");
return;
}
MethodInfo doSomethingMethodInfo =
theSingletonType.GetMethod(doSomethingMethodName );
FieldInfo field = theSingletonType.GetField("instance",
BindingFlags.Static | BindingFlags.Public);
object instance = field.GetValue(null);
string msg = (string)doSomethingMethodInfo.Invoke(instance, Type.EmptyTypes);
Console.WriteLine(msg);
MethodInfo somethingElse = theSingletonType.GetMethod(
doSomethingElseMethodName );
msg = (string)doSomethingElse.Invoke(instance, Type.EmptyTypes);
Console.WriteLine(msg);}

Categories

Resources