How to get delegate name inside delegated method?
Here is my program for testing:
namespace Test
{
class Program
{
public Action action;
void real()
{
// I hoped it would output "action" here, but it was "real"
Console.WriteLine(MethodInfo.GetCurrentMethod().Name);
}
public Program()
{
action = real;
}
static void Main(string[] args)
{
Program pr = new Program();
pr.action();
}
}
}
So how can I get the name of delegate action instead of method read?
I've tried MethodInfo.GetCurrentMethod(), but it didn't work.
Consider
static void Main(string[] args)
{
Program pr = new Program();
Action tempName1 = pr.action;
Action tempName2 = tempName1;
//pr.action();
tempName2();
}
Which name would you like to get? tempName1, tempName2, pr.action or just action?
From these choices it follows that you can't get an unambiguous variable name.
Related
Is is posible to get how you named object from the object
For example:
public static void Main(string[] args)
{
Test testVariable = new Test();
}
class Test
{
public Test()
{
Console.WriteLine(GetName());
}
}
would be testVariable
From your code example, it looks like you want the name of the assigned variable. This is not possible without specific requirements on the caller.
There is no real robust solution in C# for this.
The best you can do is using the nameof expression:
public static void Main(string[] args)
{
Test testVariable = new Test(nameof(testVariable));
}
class Test
{
public Test(string variableName)
{
Console.WriteLine(variableName);
}
}
However, this will add little benefit. As you can see, it is a 'static' solution in that it requires to pass in the name of the variable at compile time. Using nameof makes this 'refactor friendly' and gives you basic compile time checking:
public static void Main(string[] args)
{
Test testVariable = new Test(nameof(tstVariable)); // compiler error
}
It opens scenarios like this:
public static void Main(string[] args)
{
Test testVariable1 = new Test(nameof(testVariable1));
Test testVariable2 = new Test(nameof(testVariable2));
}
But as mentioned, this doesn't add very much value, and it's still error prone. For example, nothing stops you from doing something like this:
public static void Main(string[] args)
{
Test testVariable1 = new Test(nameof(testVariable1));
Test testVariable2 = new Test(nameof(testVariable1)); // oops, should be testVariable2
}
Also, as #derpirscher points out, it doesn't stop you from things like this:
Test testVariable1 = new Test(nameof(testVariable1));
Test testVariable2 = testVariable1;
testVariable2.Test(); // still outputs "testVariable1"
I am not able to invoke a delegate when passing an anonymous function.
Here is the code.
public class MethodCollection
{
public static void Print(Action<int, int> printNumbers)
{
}
}
public class Program
{
static void Main(string[] args)
{
MethodCollection.Print((p, q) => { p = q = 3; Console.WriteLine(p + q); });
Console.ReadLine();
}
}
The output is a blank screen.
The program does not print the expected output, i.e. 6.
Just call printNumbers.Invoke(3,3); or so in your Print method.
You should remove the p = q = 3; in your action because as Jon mentioned this will make your action ignore the numbers you pass the action.
Or it can be something like this... and I think you should see delegates basics first
helpful link to learn basics of delegates
public class MethodCollection
{
public static void Print(Action<int, int> printNumbers)
{
printNumbers.Invoke(0,0);
}
}
public class Program
{
static void Main(string[] args)
{
MethodCollection.Print((p, q) => { Console.WriteLine((p=3) + (q=3)); });
Console.ReadLine();
}
}
How to get the name of the class and the name of the method of this class at runtime. The code gets compiled and then obfuscated using some open source obfuscator. Here is an example:
class MainClass {
public static void Main(string[] args) {
Console.WriteLine(nameof(Test));
Console.WriteLine(nameof(Test.TestMethod));
Console.ReadLine();
}
}
class Test {
public static void TestMethod() {
Console.WriteLine("Hello World!");
}
}
The obfuscator renames classes and methods like this:
MainClass -> A
MainClass.Main -> A.a
Test -> B
Test.TestMethod -> B.a
When I run my code after compilation and obfuscation I get:
B
TestMethod
So the nameof works as expected for the class name, but doesn't work for the method name. How does the nameof work? What is the correct way to get the obfuscated names of the class and the method at runtime?
Use the following:
class MainClass {
public static void Main(string[] args) {
var methodinfo = typeof(Test).GetMethod("TestMethod");
var handle = methodinfo.MetaDataToken;
MethodBase method = System.Reflection.MethodBase.GetMethodFromHandle(handle);
string methodName = method.Name;
string className = method.ReflectedType.Name;
string fullMethodName = className + "." + methodName;
Console.WriteLine(fullMethodName);
Console.ReadLine();
}
}
class Test {
public static void TestMethod() {
Console.WriteLine("Hello World!");
}
}
I hope this is a simple question. I'm building a simple console application in C#. I have a class:
using System;
using Filter;
public class Params
{
public string key;
public bool distinct;
public List<string> fields;
public string filter;
public int limit;
public int skip;
public bool total;
public List<Tuple<string, GroupType>> group;
public List<Tuple<string, OrderType>> order;
public Params()
{
key = "";
distinct = false;
fields = new List<string>();
filter = "";
group = new List<Tuple<string, GroupType>>();
limit = 0;
order = new List<Tuple<string, OrderType>>();
skip = 0;
total = false;
}
public void AddGroup(string field, GroupType type)
{
group.Add(new Tuple<string, GroupType>(field, type));
}
public void AddOrder(string field, OrderType type)
{
order.Add(new Tuple<string, OrderType>(field, type));
}
}
My program .cs class is:
namespace csharpExample
{
class Program
{
public static void Main(string[] args)
{
Params p = new Params();
Console.WriteLine("Test");
}
}
}
I want to use Params in my program.cs class where Main() is called. I thought I could simply use Params like above. I've also tried to do a using Params; both of these are errors in VS since it can't find the directive. I've also tried adding my own namespace: namespace MyNameSpace; around my Params class. When I do this I still am unable to do a using MyNameSpace; statement as it can't find it.
I just want to extract out a bunch of functions into a class that I can reuse. How do i call this class once it's created?
-Thanks
Thanks for the help.
If you want to access the Params object in the Main function, just add Params p = new Params (); to the Main function at the top.
Most likely your problem is that Main is static, meaning that it can't access other things that aren't static which are outside of it. If you declared Params in the Program class, unless you made it static, it can't be accessed in Main.
Are you talking about calling the constructor or the properties you are setting? You can set the class at the top of your base class and then call the instance of it. But since it is a static class you should probably use a helper method in the main.
namespace Example
{
public class Program
{
Params p = new Params();
string writefromParams() // I exist just to give the string back from params with a nonstatic method
{
return p.key;
}
static void Main(string[] args)
{
Program p2 = new Program(); // set up a new instance of this very class
Console.WriteLine(p2.writefromParams()); // get non static method from class
Console.ReadLine();
}
}
}
I need to get MethodInfo for method called in Action delegate in order to check, whether methods called in Action has MyCustomAttibute
public void Foo( Action action )
{
if(Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
{
throw new ArgumentException("Invalid action");
}
}
The Foo method should be able to be called as following:
Foo(() =>
{
instanceOfFooClass.Method1().Method2();
});
In Foo method I want to be sure that Method1 and Method2 has MyCustomAttribute. However action.Method is giving me the MethodInfo, which is the action of delegate, which happens when using lambda expression. Is there any way to get Method1 and Method2 MethodInfo?
As mentioned in the comments, Expression<T> is probably the best way to achieve this. However, it requires a Compile() at runtime so it should be performance profiled.
With Expression<T> you can easily get access to Method info like this:
public MethodInfo GetMethodInfo(Expression<Action> action)
{
return ((MethodCallExpression)action.Body).Method;
}
But, before executing the action you must do this:
private void InvokeMethod(Expression<Action> action)
{
action.Compile().Invoke();
}
EDIT
Ah yes, I forgot how to get access to the customer attribute. You would do it like this:
var methodInfo = ((MethodCallExpression)myAction.Body).Method;
var attributes = methodInfo.GetCustomAttributes<T>(true);
EXAMPLE
Here is an example showing passing chained method calls to Expression<Action>:
public class ActionTest
{
public void DoAction(Action action)
{
action();
}
public void DoExpressionAction(Expression<Action> action)
{
var method2Info = ((MethodCallExpression)action.Body).Method;
// a little recursion needed here
var method1Info = ((MethodCallExpression)((MethodCallExpression)action.Body).Object).Method;
var myattributes2 = method2Info.GetCustomAttributes(typeof(MyAttribute), true);
var myattributes1 = method1Info.GetCustomAttributes(typeof(MyAttribute), true);
action.Compile().Invoke();
}
}
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
private string message;
public MyAttribute(string message)
{
this.message = message;
}
}
public class MethodTest
{
[MyAttribute("Number1")]
public MethodTest Method1()
{
Console.WriteLine("Action");
return this;
}
[MyAttribute("Number2")]
public MethodTest Method2()
{
Console.WriteLine("ExpressionAction");
return this;
}
}
class Program
{
static void Main(string[] args)
{
ActionTest target = new ActionTest();
MethodTest instance = new MethodTest();
target.DoExpressionAction(() => instance.Method1().Method2() );
Console.ReadLine();
}
static void Method1()
{
Console.WriteLine("Action");
}
static void Method2()
{
Console.WriteLine("ExpressionAction");
}
}
If you call your Foo() methdod like this:
Foo(instanceOfFooClass.Method);
Your code works as you'd expect (void methods are actions, after all).
On a side note, I think "chaining" method calls in fact counts as you're only passing the last one through.
Full sample demonstrating the behavior:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
class MyCustomAttribute : Attribute { }
class FooClass
{
[MyCustom]
public void DecoratedMethod() { Console.WriteLine("Decorated Method - executed."); }
public void NotDecoratedMethod() { Console.WriteLine("Not Decoreated Method - executed."); }
}
class Program
{
static void Main(string[] args)
{
FooClass instanceOfFooClass = new FooClass();
Foo(instanceOfFooClass.DecoratedMethod);
Foo(instanceOfFooClass.NotDecoratedMethod);
Console.ReadLine();
}
public static void Foo(Action action)
{
if (Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
Console.WriteLine(string.Format("Invalid method {0}", action.Method.Name));
else
{
Console.WriteLine(string.Format("Valid method {0}", action.Method.Name));
action.Invoke();
}
}
}
}