Question on calling a method using reflection - c#

Beautiful sunny day today! However, I can't enjoy it because I've been trying to call a dynamic method in Mono for 2 days :-(
The Story:
I'm trying to call it within a class called 'Template'. Basically I would love it if I could pass a string to Template and have it run that method, which is defined within the Template class. The template class looks like this so far..
namespace Mash
{
public class Template
{
public Template(string methodToCall)
{
Type type = this.GetType();
object ob = Activator.CreateInstance(type);
object[] arguments = new object[52];
type.InvokeMember(methodToCall,
BindingFlags.InvokeMethod,
null,
ob,
arguments);
}
public void methodIWantToCall()
{
Console.WriteLine("I'm running the Method!");
}
}
}
No errors are received during compile time. Once I run it, however, I get
'Unhandled Exception: System.MissingMethodException: Method not found: 'Default constructor not found...ctor() of Mash.Template'.'
I think it is failing here:
object ob = Activator.CreateInstance(type);
If you need any more information please let me know.
Thanks in advance!!

you don't need another instance of Template if the method you want to call is in the same class.You can use this
public class Template
{
public Template(string methodToCall)
{
this.GetType().InvokeMember(methodToCall,
BindingFlags.InvokeMethod,
null,
this,
null);
}
public void methodIWantToCall()
{
Console.WriteLine("I'm running the Method!");
}
}
I tested it with:
class Program
{
public static void Main(string[] args)
{
Template m = new Template("methodIWantToCall");
Console.ReadKey(true);
}
}

The first argument of Activator.CreateInstance is the type of the class, and then follows the argument of the constructor of the type.
You're trying to create an instance of the Template class using no parameter for the constructor. But there isn't a constructor with no parameter.
Try adding a constructor into your Template class, which takes no parameters:
public class Template
{
//......
public Template()
{
}
}

Related

In C# [AttributeUsage(AttributeTargets.Parameter)] Is not working

While creating a custom attribute of "AttributeTargets.Parameter" constructor is not called. I want to use the parameter value of Fn function under Test Class. I used .net core and .net standard.
class Program
{
public static void Main()
{
var test = new Test();
test.Fn("Hello");
Console.WriteLine("end");
Console.Read();
}
}
public class Test
{
public void Fn([Parameter] string parm)
{
Console.WriteLine(parm);
}
}
[AttributeUsage(AttributeTargets.Parameter)]
public class ParameterAttribute : Attribute
{
public ParameterAttribute()
{
Console.WriteLine("In Parameter Attribute");
}
}
As far as I remember, Attribute constructors are only executed when you start inspecting the type and not when an instance of that type is created or a method executed (in your case).
You can take a look at this answer for a detailed example of the order of execution when using custom Attributes.
Hope it helps!

How to get the name of the class which contains the method which called the current method?

I have a requirement where I need to know the name of the class (ApiController) which has a method (GetMethod) which is called by another method (OtherMethod) from a different class (OtherClass).
To help explain this, I hope the below pseudo-code snippets help.
ApiController.cs
public class ApiController
{
public void GetMethod()
{
OtherMethod();
}
}
OtherClass.cs
public class OtherClass()
{
public void OtherMethod()
{
Console.WriteLine(/*I want to get the value 'ApiController' to print out*/)
}
}
What I've tried:
I've looked at How can I find the method that called the current method? and the answers will get me the calling method (OtherMethod) but not the class (ApiController) which has that method
I tried [CallerMemberName] and using StackTrace properties but these don't get me the method's class name
using System.Diagnostics;
var className = new StackFrame(1).GetMethod().DeclaringType.Name;
Goes to the previous level of the Stack, finds the method, and gets the type from the method. This avoids you needing to create a full StackTrace, which is expensive.
You could use FullName if you want the fully qualified class name.
Edit: fringe cases (to highlight the issues raised in comments below)
If compilation optimizations are enabled, the calling method may be inlined, so you may not get the value you expect. (Credit: Johnbot)
async methods get compiled into a state machine, so again, you may not get what you expect. (Credit: Phil K)
So it can be done like this,
new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType.Name
StackFrame represents a method on the call stack, the index 1 gives you the frame that contains the immediate caller of the currently executed method, which is ApiController.GetMethod() in this example.
Now you have the frame, then you retrieve the MethodInfo of that frame by calling StackFrame.GetMethod(), and then you use the DeclaringType property of the MethodInfo to get the type in which the method is defined, which is ApiController.
You can achieve this by below code
First you need to add namespace using System.Diagnostics;
public class OtherClass
{
public void OtherMethod()
{
StackTrace stackTrace = new StackTrace();
string callerClassName = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
string callerClassNameWithNamespace = stackTrace.GetFrame(1).GetMethod().DeclaringType.FullName;
Console.WriteLine("This is the only name of your class:" + callerClassName);
Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
}
}
The instance of stackTrace is depend upon your implementation environment. you may defined it locally or globally
OR
You may use below method without creating StackTrace instance
public class OtherClass
{
public void OtherMethod()
{
string callerClassName = new StackFrame(1).GetMethod().DeclaringType.Name;
string callerClassNameWithNamespace = new StackFrame(1).GetMethod().DeclaringType.FullName;
Console.WriteLine("This is the only name of your class:" + callerClassName);
Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
}
}
Try this may it help you
Why not simply pass the name as constructor parameter? This doesn't hide the dependency, unlike StackFrame/StackTrace.
For example:
public class ApiController
{
private readonly OtherClass _otherClass = new OtherClass(nameof(ApiController));
public void GetMethod()
{
_otherClass.OtherMethod();
}
}
public class OtherClass
{
private readonly string _controllerName;
public OtherClass(string controllerName)
{
_controllerName = controllerName;
}
public void OtherMethod()
{
Console.WriteLine(_controllerName);
}
}

Invoke abstract class method using reflection c#

My external dll design looks like :
class Engineering
{
ProjectsCollection project {get;}
}
abstract class ProjectsCollection
{
public abstract Project Open(string path);
}
I'm able to proceed till getting the method info
MethodInfo info = type.GetMethod("Open");
How to invoke the method "Open"?
Reflection or not, you cannot invoke an abstract method, because there is nothing to invoke. Sure, you can write
info.Invoke(eng.project, new object[] {path});
but it will throw an exception unless eng.project is set to an object of a non-abstract class descendent from ProjectCollection, which implements the Open method:
class ProjectsCollectionImpl : ProjectsCollection {
public Project Open(string path) {
return ...
}
}
Engineering eng = new Engineering(new ProjectsCollectionImpl());
MethodInfo info = type.GetMethod("Open");
var proj = info.Invoke(eng.project, new object[] {path});
Just call Invoke!
info.Invoke(someObject, new object[] {"This is the parameter of the method"});
Simple as that!
The return value of Invoke will be the return value of Open, which should be a Project object.
From the docs:
Invokes the method or constructor represented by the current instance, using the specified parameters.
Oh, and you should know that someObject above is the object that you're calling the method on. You should always make it an instance of a concrete class! Don't give it null!

Activator.CreateInstance throws MissingMethodException in 1 solution but not another

I am having a strange error in one of my solutions while attempting to use Activator.CreateInstance having changed the parameter for the .ctor on the type being created from a plain generic T to an IEnumerable. I have extracted enough code to a console app to test in isolation but it appears to work just fine.
Below is the extracted code that works in the console app -
class Program
{
static void Main(string[] args)
{
Notify(new List<MyBase> { new MyBase(), new MyBase() });
}
private static void Notify<T>(IEnumerable<T> changes) where T : IMy
{
var dtoType = changes.First().GetType();
var type = typeof(MyNotification<>).MakeGenericType(dtoType);
var notification = (IMyNotification)Activator.CreateInstance(type, new object[] { changes });
}
}
public interface IMy { }
public class MyBase : IMy { }
public interface IMyNotification { }
public interface IMyNotification<T> : IMyNotification where T : IMy
{
}
public class MyNotification<T> : IMyNotification<T> where T : IMy
{
public MyNotification(IEnumerable<T> mys) { }
}
Essentially this is the same code as is running in my original solution.
The error is a MissingMethodException, so it cannot find a matching .ctor.
Run out of ideas on what could be causing this, looking at the type information in the debugger for both solutions I cannot see any difference. All projects are cleaned and built with the solution.
edit
Hoping someone can point me in another direction to potentially solve this issue.
Thanks
edit
I have tried changing the .ctor to be of type 'object' and with that change Activator can create the type.
Just use new MyNotification<T>(changes) if it is what you need.

Triggering a non-static class from a static class?

I am writing a class library(API) in C#. The class is non-static and contains several public events. Is it possible to trigger those events from a static method in a separate class?
For example...
class nonStaticDLLCLASS
{
public event Event1;
public CallStaticMethod()
{
StaticTestClass.GoStaticMethod();
}
}
class StaticTestClass
{
public static GoStaticMethod()
{
// Here I want to fire Event1 in the nonStaticDLLCLASS
// I know the following line is not correct but can I do something like that?
(nonStaticDLLCLASS)StaticTestClass.ObjectThatCalledMe.Event1();
}
}
I know you typically have to create an instance of the non-static class in order to access it's methods but in this case an instance has already been created, just not by the class that is trying to access it.
No, instance members can only be invoked/accessed on a valid instance of the type.
In order for this to work you must pass an instance of nonStaticDLLCLASS to StaticTestClass.GoStaticMethod and use that instance reference to invoke/access the non-static members.
In your example above how do you specify which instance of the type you are accessing? The static method has no knowdlege of any instance so how does it know which one to use or if there are any loaded in memory at all?
Consider this example:
using System;
class Dog
{
public String Name { get; set; }
}
class Example
{
static void Main()
{
Dog rex = new Dog { Name="Rex" };
Dog fluffy = new Dog { Name="Fluffy" };
}
static void sayHiToDog()
{
// In this static method how can I specify which dog instance
// I mean to access without a valid instance? It is impossible since
// the static method knows nothing about the instances that have been
// created in the static method above.
}
static void sayHiToDog(Dog dog)
{
// Now this method would work since I now have an instance of the
// Dog type that I can say hi to.
Console.WriteLine("Hello, " + dog.Name);
}
}
Instance methods can only be called on instances. In your example, the instance is calling the static method. Can you give the static method a parameter allowing the instance to pass in a reference to itself? Something like this:
class nonStaticDLLCLASS
{
public event Event1;
public CallStaticMethod()
{
StaticTestClass.GoStaticMethod(this);
}
}
class StaticTestClass
{
public static GoStaticMethod(nonStaticDLLCLASS instance)
{
// Here I want to fire Event1 in the nonStaticDLLCLASS
// I know the following line is not correct but can I do something like that?
instance.Event1();
}
}
I think you need to clarify your question to specify why you can't do something like this, or why the instance can't raise its own event.

Categories