How to get the object from a MethodBase class instance - c#

I have a module (Fody.MethodTimer) that I can extend my classes with attributes. When my class'es method gets executed it, invokes a static method (in another class)
public class CommandBase
{
[Time]
public bool test()
{
return true;
}
}
public static class MethodTimeLogger
{
public static void Log(MethodBase methodBase, long milliseconds)
{
//Do some logging here
}
}
Basically, after the method is call of test is complete, the Log method gets executed. As you can see, it get a MethodBase argument and has all that is needed do decribe the method that invoked this method call.
my Question is, If it is possible to get the object that invoked the Log method Call, out of The .NET MethodBase class instance.

No. MethodBase is extracted from a type, not an instance. You will need to pass the instance in as a parameter if you want to invoke methods on it.
Even if you could, how would you know what parameter values to use when calling the method?
This is why all built-in event handlers have an object sender parameter - so you know which object triggered the event.

Related

Delegate a method call, to another method

I am not sure if what I am looking for is even possible, but I wonder if there is a way to delegate a method, when it is called, to another method. Let's say I have a declared object Receiver with a public method OnReceived(string param), inside a class ReceiverMiddleMan. When this method is called on Receiver, I would like to pass the parameters of this method to a method OnReceivedInMiddleMan somehow, not necessarily in the way as is shown in the code. Why? Because I would like to know if the data in Receiver.OnReceived can be got directly, without for instance inheriting from Receiver to access the method. The Receiver class, used here as an example, is in real life a Third party library which I cannot modify with events and such. The only access I have is the public method.
class Receiver
{
public void OnReceived(string param)
{
//do something
}
}
class ReceiverMiddleMan
{
Receiver receiver = new Receiver();
Listen(receiver.OnReceived);
public void Listen(Method method)
{
OnReceivedInMiddleMan(method.param);
}
public void OnReceivedInMiddleMan(string param)
{
//do something
}
}

how to log the function calls without calling logger functions inside every function

I am logging the function calls into a log file.
I am using log4Net for the same
public Registration Check(Registration registration)
{
loggingProvider.Entry();
//Some code Here
loggingProvider.Exit();
return something;
}
Now if i have to make an entry of a function call i have to manually add loggingProvider.Entry() inside every function.
Is there a way where I can log all function calls happening inside a given namespace with minimal LOC? Like writing a function in just one place which will log all functions calls happening?
I tried to get the name of the function being called from the constructor/destructor using the stacktrace and log it but its not possible.
Please provide me any alternate way to get the function names that are being called without manually adding log function inside each and every function.
Postsharp would be able to help with this.
http://www.postsharp.net/
Look at injecting behaviour before and after method invocation on http://doc.postsharp.net/method-decorator
As an example, this was taken from their site
[Serializable]
public sealed class TraceAttribute : OnMethodBoundaryAspect
{
// This field is initialized and serialized at build time, then deserialized at runtime.
private readonly string category;
// These fields are initialized at runtime. They do not need to be serialized.
[NonSerialized] private string enteringMessage;
[NonSerialized] private string exitingMessage;
// Default constructor, invoked at build time.
public TraceAttribute()
{
}
// Constructor specifying the tracing category, invoked at build time.
public TraceAttribute(string category)
{
this.category = category;
}
// Invoked only once at runtime from the static constructor of type declaring the target method.
public override void RuntimeInitialize(MethodBase method)
{
string methodName = method.DeclaringType.FullName + method.Name;
this.enteringMessage = "Entering " + methodName;
this.exitingMessage = "Exiting " + methodName;
}
// Invoked at runtime before that target method is invoked.
public override void OnEntry(MethodExecutionArgs args)
{
Trace.WriteLine(this.enteringMessage, this.category);
}
// Invoked at runtime after the target method is invoked (in a finally block).
public override void OnExit(MethodExecutionArgs args)
{
Trace.WriteLine(this.exitingMessage, this.category);
}
}
Methods that need to be traced(logged in your case) can be decorated by using [Trace], it should also be possible to create a class level aspect, where you can decorate the class that should have the logging associated, although I haven't done that myself.

Reflection attribute method

I have an asbtract class and I have classes that are devired from it. I have an attribute called PluginEventAttribute that works like so:
[PluginEventAttribute(PluginEvent.Load)]
public void OnLoad()
{
Log("Test Plugin loaded!");
}
I want my code to check if there is a method that uses that attribute, and if so, call it with custom parameters. How can I do that in C# winforms?
You just have to enumerate the instance methods and call the method if it has said attribute. Here's a working example (I hope I got your intent correctly) :
using System;
using System.Reflection;
class Program
{
class MyAttr : Attribute { }
abstract class Base { };
class Derived : Base
{
[MyAttr]
public void foo() { Console.WriteLine("foo"); }
public void bar() { Console.WriteLine("bar"); }
}
static void Main()
{
Base someInstance = new Derived();
foreach (var m in someInstance.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
{
if (m.GetCustomAttribute(typeof(MyAttr)) != null)
{
m.Invoke(someInstance, null); // prints "foo"
}
}
Console.ReadLine();
}
}
You may change the null argument in the call to Invoke to the array of arguments you wish to pass to the function. The contents of that array must match the function signature.
This has nothing to do with WinForms. It's all about CLR runtime and its type system.
I don't know any way how you could "just do it".
You can check if a method M has an attribute A only if you have a MethodInfo object that describes that method (methodinfo.GetCustomAttributes())
You can get MethodInfos in several ways, but the easiest and most obvious is to get the Type object and ask it about its methods (type.GetMethod()/type.GetMethods()).
You can get a Type object in several ways too. If you have any object at hand, you can call its GetType() method. Or, you can ask an Assembly object (that describes a DLL or EXE) about the Types it defines. (..)
So, if you have a foo object that someone already created:
call foo.GetType()
loop over type.GetMethods()
call method.GetCustomAttributes(typeof(YourAttribute))
check if it was found
Now if you notice that it as been found, you will end up having a MethodInfo that matches a method with that attribute. The only thing left is to call that method with methodinfo.Invoke and to pass it both parameters and the foo object.
Situation gets tricky if you don't have a foo object that you want to scan for methods. You must get the whole assembly, scan all types, scan all their methods. You end up with matching MethodInfo again. But you don't have any object to call the method found upon. Either that method will need to be static (so callable without target object) or you will need to somehow get matching object, too.

Explicitly call static constructor

I want to write unit test for below class.
If name is other than "MyEntity" then mgr should be blank.
Negative Unit test
Using Manager private accessor I want to change name to "Test" so that mgr should be null.
And then will verify the mgr value.
To achieve this, I want to explicitly call the static constructor
but when I call the static constructor using
Manager_Accessor.name = "Test"
typeof(Manager).TypeInitializer.Invoke(null, null);
name is always set to "MyEntity" how to set name to "Test" and invoke the static constructor.
public class Manager
{
private static string name= "MyEntity";
private static object mgr;
static Manager()
{
try
{
mgr = CreateMgr(name);
}
catch (Exception ex)
{
mgr=null;
}
}
}
As I found out today, the static constructor CAN be called directly:
from another Stackoverflow post
The other answers are excellent, but if you need to force a class
constructor to run without having a reference to the type (ie.
reflection), you can use:
Type type = ...;
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle);
I had to add this code to my application to work around a possible bug in the .net 4.0 CLR.
For anyone finding this thread and wondering... I just did the test. It appears System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor() will only run the static constructor if it has not already been run for another reason.
For example, if your code isn't positive whether or not previous code may have accessed the class and triggered the static constructor to run, it doesn't matter. That previous access will have triggered the static constructor to run, but then RunClassConstructor() will not run it also. RunClassConstructor() only runs the static constructor if it hasn't already been run.
Accessing the class after RunClassConstructor() also does not result in the static constructor being run a second time.
This is based on testing in a Win10 UWP app.
Just add public static void Initialize() { } method to your static class and call it when you want. This is very similar to call constructor, because static constructor will be called automatically.
If you have a static member in your class (there must be, otherwise static constructor wouldn't do too much) then no need to explicitly call the static constructor.
Simply access the class where you would like to call its static constructor.
E.g.:
public void MainMethod()
{
// Here you would like to call the static constructor
// The first access to the class forces the static constructor to be called.
object temp1 = MyStaticClass.AnyField;
// or
object temp2 = MyClass.AnyStaticField;
}

Passing object reference to method, must it be static?

When I'm trying some code to learn about passing a reference of an object to a method, I get an error when I try to remove the static in the methods head. The error message says: An object reference is required for non-static field, method or property...... But isn't there a reference in the parameter already? I have seen code that don't use static, so why does this not work? I know that static is used when method is used from classes that isn't objects. Some explanation is appreciated to understand. Thanks!
// Method
internal static string ChangeName(Box obj)
{
return obj.BoxName;
}
EDIT: I added the whole code. Is the problem that I'm calling from inside the main method that is static?
class Program
{
static void Main(string[] args)
{
Box box1, box2;
box1 = new Box("Nick","R90",1);
box2 = new Box("Hanna","B27",2);
Console.WriteLine(ChangeName(box2));
Console.Read();
}
// Methods
private static string ChangeName(Box obj)
{
return obj.BoxName;
}
}
A static method is called like this:
MyClass.Method(arg);
An instance method is called like this:
MyClass myInstance = new MyClass();
myInstance.Method(arg);
The two are not compatible.
If you want to change the method signature, you also need to change every place where the method is called.
EDIT: You are using the unqualified call. Here are the rules for using an unqualified call.
A static method can call a static method.
A static method cannot call an instance method. (This is your problem.)
An instance method can call a static method.
An instance method can call an instance method.
This method should really be implemented as an instance method in the Box class. You would then say:
Console.WriteLine(box2.ChangeName());
If you don't have access to the Box code, and then you could either write an extension method, or keep the method static as per your example.
Probably the error is where you are calling this method; if you are calling from a static method, you must call against an object instance explicitly or call a static method.

Categories