We have encountered some strange things while calling reflected generic delegates. In some cases with attatched debuger we can make impossible call, while without debugger we cannot catch any exception and application fastfails.
Here is the code:
using System;
using System.Windows.Forms;
using System.Reflection;
namespace GenericDelegate
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate Class2 Delegate1();
private void button1_Click(object sender, EventArgs e)
{
MethodInfo mi = typeof (Class1<>).GetMethod("GetClass", BindingFlags.NonPublic | BindingFlags.Static);
if (mi != null)
{
Delegate1 del = (Delegate1) Delegate.CreateDelegate(typeof (Delegate1), mi);
MessageBox.Show("1");
try
{
del();
}
catch (Exception)
{
MessageBox.Show("No, I can`t catch it");
}
MessageBox.Show("2");
mi.Invoke(null, new object[] {});//It's Ok, we'll get exception here
MessageBox.Show("3");
}
}
class Class2
{
}
class Class1<T> : Class2
{
internal static Class2 GetClass()
{
Type type = typeof(T);
MessageBox.Show("Type name " + type.FullName +" Type: " + type + " Assembly " + type.Assembly);
return new Class1<T>();
}
}
}
}
There are two problems:
Behavior differs with debugger and without
You cannot catch this error without debugger by clr tricks. It's just not the clr exception. There are memory acces vialation, reading zero pointer inside of internal code.
Use case:
You develop something like plugins system for your app. You read external assembly, find suitable method in some type, and execute it. And we just forgot about that we need to check up is the type generic or not. Under VS (and .net from 2.0 to 4.0) everything works fine. Called function does not uses static context of generic type and type parameters. But without VS application fails with no sound. We even cannot identify call stack attaching debuger.
Tested with .net 4.0
The question is why VS catches but runtime do not?
Well, yes, that doesn't behave very gracefully. It is partly fixed in .NET 4.0, the CreateDelegate() method returns null. That still doesn't behave gracefully when the JIT optimizer is enabled though, it assumes that CreateDelegate cannot return null and doesn't perform a null check. You'll get a FatalExecutionEngineError instead of NRE, an exception that is no longer catchable in 4.0
I'd recommend you report the defect to connect.microsoft.com. Not so sure they'll take you seriously, I don't know what their policy is when you intentionally bypass the safeguards. It could well be that they consider the FEEE good enough. The workaround is obvious, only call methods of concrete types.
I'm not sure I follow exactly what you want to do, but if you put your code in a try/catch block there certainly is an exception thrown.
Just tested under VS 2008
VS does not catch exception at all.
Here is modified test case
static class Program
{
private delegate Foo Delegate1();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MethodInfo mi = typeof(Bar<>).GetMethod("GetClass", BindingFlags.NonPublic | BindingFlags.Static);
if (mi != null)
{
var del = (Delegate1)Delegate.CreateDelegate(typeof(Delegate1), mi);
MessageBox.Show("1");
try
{
del();
//mi.Invoke(null, BindingFlags.NonPublic | BindingFlags.Static, null, null,CultureInfo.InvariantCulture);
}
catch (Exception)
{
MessageBox.Show("No, I can`t catch it");
}
MessageBox.Show("2");
mi.Invoke(null, new object[] { });//It's Ok, we'll get exception here
MessageBox.Show("3");
}
}
class Foo
{
}
class Bar<T> : Foo
{
internal static Foo GetClass()
{
Type type = typeof(T);
MessageBox.Show("Type name " + type.FullName + " Type: " + type + " Assembly " + type.Assembly);
return new Bar<T>();
}
}
}
but if you comment del() und uncomment mi.Invoke() you will get nice exception
true.
Late bound operations cannot be
performed on types or methods for
which ContainsGenericParameters is
true
I don't think that the code you posted actually works under the .net framework vers. 2.0 to 4.0. Static methods can be called AFAIK only on closed generic types, not on opened generic types. So you'll have to provide a type parameter. As for the debugger, try to launch your process outside Visual Studio and then attach the VS-Debugger. This time you'll get the expected exception right away.
Related
Essentially I am creating a little IL injection DLL that uses MONO.CECIL and C#, primarily as a learning exercise for myself but also for my own future hobbyist use.
I am not particularly skilled with exceptions (or C#) and am unsure what the appropriate exception to throw is for when a runtime type mismatch occurs.
For example : I have a method that INJECTS a method call at a given point in a target DLL. The method takes as an arguement a Collection (parameters) to represent the variables to pass as parameters to the newly injected method call.
Before injecting I check for type parity between each member of the Collection (parameters) and the Collection from the method whose call I am injecting.
On a mismatch I want to throw an exception. But I could not really find any that fit. I would prefer to use existing exceptions where possible, rather than creating my own.
Here is the code :
private static bool ParameterParity(Collection<ParameterDefinition> p, Collection<VariableDefinition> v)
{
if (p.Count != v.Count)
{
return (false);
}
else
{
int index = 0;
foreach (ParameterDefinition parameter in p)
{
if (parameter.ParameterType.MetadataType != v[index].VariableType.MetadataType)
{
return (false);
}
index++;
}
}
return (true);
}
Here is the call where the exception will be thrown :
if (ParameterParity(source.Parameters, parameters) == false)
{
throw new NotImplementedException($"{Helper.AddParenthesis(nameof(PreInject), Helper.ParenthesisE.Square)}" +
$" : Parameter mismatch in TYPE or NUMBER" +
$". Functionality not supported.");
}
I temporarily have used the NOT IMPLEMENTED exception, but would prefer something more appropriate. A suggestion as to the appropriate Exception would be appreciated.
Thanks in advance.
Imagine the following situation:
Assembly A is starting the program. (it has a main method)
it loads Assembly B via reflection and instantiates a class of Assembly B.
in this instance a method is called where i would like to get to the Assembly B.
i have already tried
System.Reflection.Assembly.GetCallingAssembly();
System.Reflection.Assembly.GetExecutingAssembly();
but they always give me Assembly A instead of B.
Try getting type of class contain the method you are going for and get its assembly.
string assemblyName = this.GetType().Assembly.FullName;
The Assembly.GetExecutingAssembly() is the proper method to use.
You leave preciously few breadcrumbs to diagnose the cause of having trouble with it. There are however strings attached to this. An important job performed by the jitter is to make methods disappear. This is an optimization called "inlining". In effect, the call to the method is replaced by the code of the method. It is a very important optimization, it for example makes properties as cheap as using public fields. But a consequence it that you'll get the assembly of the calling method. In your case Main(). So you'll see assembly A and not B.
This is not something you ought to tinker with, avoid having a need for this. A method shouldn't be puzzled about what assembly it lives in, you could for example use the typeof(T).Assembly property where T is the class in which the method lives.
You can disable the inlining optimization, you do so with an attribute:
using System.Runtime.CompilerServices;
...
[MethodImpl(MethodImplOptions.NoInlining)]
public void Foo() { }
try this sample ,
public static object ExecuteAssemblyMethod(string methodName,Type assemblyObj, object[] arguments)
{
object result = null;
try
{
object ibaseObject = Activator.CreateInstance(assemblyObj);
result = assemblyObj.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, ibaseObject, arguments);
}
catch (ReflectionTypeLoadException emx)
{
result = null;
return result;
}
catch (Exception ex)
{
result = null;
return result;
}
return result;
}
Usage:-
Assembly assemb = Assembly.LoadFile(#"D:\TEMP\TestClassLibrary_new.dll");
Type testType = assemb.GetType("TestClassLibrary.Class1");
object[] param = new object[] {"akshay" };
object result = LoadAssembly.ExecuteAssemblyMethod("GetName", testType, param);
How do I know the log the last property that is null?
For example,
var a = "somevalue";
......
......
if(a == null)
{
Log.Error(MethodBase.GetCurrentMethod().Name + "Property : a is null");
//blah blah
}
Like how I use the reflection to get the current method name, there should be some means by which I can log the latest local variables (or a property or fields)
that is being compared ? I use, log4net by the way to log the errors.
1) Is there any method to achieve this or should we manually log it?
2) Is there any custom method that prints the class -> MethodName -> Propertyname(or FieldName) that is null?
Thanks for your time in advance.
As mentioned by #fsimonazzi, "a" would be a local variable.
That being said there is still no way to examine the current compare operation as in MSIL there is no formal concept of an IF block - only conditional jumps.
If you wanted to get really crazy with the reflection, you may be able to find the current executing instruction and look around near that for a variable, but even then, you will not find the name - only a reference - as names are only used prior to compilation.
Either way, reflection is not going to help you here.
Instead, try using Exceptions - specifically ArgumentNullException. This body of code would become:
void doStuff(string param1, int param2)
{
if (param == null)
throw new ArgumentNullException("param1", "param1 must not be null");
if (param2 < 0)
throw new ArgumentOutOfRangeException("param2", "param2 should be non-negative.");
//method body
}
then, when you call the method, you can catch the exception and log it - no matter what it may be.
public static void Main(string[] args)
{
try
{
doStuff(null, 3);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Tools like FxCop can help make sure that you are properly validating each parameter.
Properties are actually implemented as methods, so reflection could help you there. If, for example, you were validating in a property and wanted to log the position automatically, you could.
private object _cachedObject = null;
public object CachedObject
{
get
{
if (_cachedObject == null)
{
log(MethodBase.GetCurrentMethod().Name, "creating cached object");
_cachedObject = createCachedObject();
}
return _cachedObject;
}
}
The .Net Framework 4.5 also brings with it a new attribute that can be used to replace the MethodBase.GetCurrentMethod().Name construct you are using to get the method name. See [CallerMemberNameAttribute][3].
Is-it possible in C# to call a method (non-static) without instantiating its class e.g :
public class MyClass
{
public void MyMethod()
{
Console.WriteLine("method called");
}
}
I've tried this method using the System.Reflection.Emit namespace, I copied the IL of MyMethod() to a dynamic method but got an exception :
FatalExecutionEngineError was detected :
The runtime has encountered a fatal error. The address of the error was at 0x5dceccf5, on thread 0x2650. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
Type t = a.GetType("Tutorial.MyClass");
MethodInfo m = t.GetMethod("MyMethod");
MethodBody mb = m.GetMethodBody();
DynamicMethod dm = new DynamicMethod("MethodAlias", null, Type.EmptyTypes, typeof(Tutorial.MainWindow), true);
DynamicILInfo ilInfo = dm.GetDynamicILInfo();
SignatureHelper sig = SignatureHelper.GetLocalVarSigHelper();
ilInfo.SetLocalSignature(sig.GetSignature());
ilInfo.SetCode(mb.GetILAsByteArray(), mb.MaxStackSize);
try
{
dm.Invoke(this, null);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Thank you
Not that I know of. Because it's not static.
I would just say "No" but my reply wasn't long enough for SO.
Update: I've filed a bug report on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/568271/debugger-halting-on-exception-thrown-inside-methodinfo-invoke#details
If you can reproduce this problem on your machine, please upvote the bug so it can be fixed!
Ok I've done some testing and I've reduced the problem to something very simple:
i. Create a method in a new class that throws an exception:
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
ii. Create a MethodInfo that points to this method somewhere else:
Type class1 = typeof( Class1 );
Class1 obj = new Class1();
MethodInfo method = class1.GetMethod( "CallMe" );
iii. Wrap a call to Invoke() in a try/catch block:
try {
method.Invoke( obj, null ); // exception is not being caught!
} catch {
}
iv. Run the program without the debugger (works fine).
v. Now run the program with the debugger. The debugger will halt the program when the exception occurs, even though it's wrapped in a catch handler that tries to ignore it. (Even if you put a breakpoint in the catch block it will halt before it reaches it!)
In fact, the exception is happening when you run it without the debugger too. In a simple test project it's getting ignored at some other level, but if your app has any kind of global exception handling, it will get triggered there as well. [see comments]
This is causing me a real headache because it keeps triggering my app's crash-handler, not to mention the pain it is to attempt to debug.
I can reproduce this on my .NET 4 box, and you're right -- it only happens on .NET 4.0.
This smells very much like a bug to me, and should go on MS Connect. Major bummer if this is tripping your crash handler. Sounds like a non-pleasing way to work around this is to wrap the invoked method inside its own handler. :-(
One thing I can not reproduce, though, is tripping the crash handler. Here's my program:
namespace trash {
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
class Program {
static void Main(string[] args) {
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
var class1 = typeof(Class1);
var method = class1.GetMethod("CallMe");
try {
var obj = new Class1();
method.Invoke(obj, null); // exception is not being caught!
}
catch (System.Reflection.TargetInvocationException) {
Console.Write("what you would expect");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
Console.Write("it would be horrible if this got tripped but it doesn't!");
}
}
}
You can't catch all exceptions. There's a few assumptions in your example. You are, for instance, assuming the exception was raised on the calling thread. Catching unhandled exceptions on other threads depends on which runtimes you're using (console, winforms, WPF, ASP.Net, etc).
Additionally, calls to System.Environment.FailFast() do not generate any handlable condition - the process is effectively terminated with no chance for intervention.