Is ConstructorInfo.GetParameters Thread-Safe? - c#

This is a very strange problem that I have spent the day trying to track down. I am not sure if this is a bug, but it would be great to get some perspective and thoughts on why this is happening.
I am using xUnit (2.0) to run my unit tests. The beauty of xUnit is that it automatically runs tests in parallel for you. The problem that I have found, however, is that Constructor.GetParameters appears to not be thread-safe when the ConstructorInfo is marked as being a thread-safe type. That is, if two threads reach Constructor.GetParameters at the same time, two results are produced, and subsequent calls to this method returns the second result that was created (regardless of the thread that calls it).
I have created some code to demonstrate this unexpected behavior (I also have it hosted on GitHub if you would like to download and try the project locally).
Here is the code:
public class OneClass
{
readonly ITestOutputHelper output;
public OneClass( ITestOutputHelper output )
{
this.output = output;
}
[Fact]
public void OutputHashCode()
{
Support.Add( typeof(SampleObject).GetTypeInfo() );
output.WriteLine( "Initialized:" );
Support.Output( output );
Support.Add( typeof(SampleObject).GetTypeInfo() );
output.WriteLine( "After Initialized:" );
Support.Output( output );
}
}
public class AnotherClass
{
readonly ITestOutputHelper output;
public AnotherClass( ITestOutputHelper output )
{
this.output = output;
}
[Fact]
public void OutputHashCode()
{
Support.Add( typeof(SampleObject).GetTypeInfo() );
output.WriteLine( "Initialized:" );
Support.Output( output );
Support.Add( typeof(SampleObject).GetTypeInfo() );
output.WriteLine( "After Initialized:" );
Support.Output( output );
}
}
public static class Support
{
readonly static ICollection<int> Numbers = new List<int>();
public static void Add( TypeInfo info )
{
var code = info.DeclaredConstructors.Single().GetParameters().Single().GetHashCode();
Numbers.Add( code );
}
public static void Output( ITestOutputHelper output )
{
foreach ( var number in Numbers.ToArray() )
{
output.WriteLine( number.ToString() );
}
}
}
public class SampleObject
{
public SampleObject( object parameter ) {}
}
The two test classes ensure that two threads are created and run in parallel. Upon running these tests, you should get results that look like the following:
Initialized:
39053774 <---- Different!
45653674
After Initialized:
39053774 <---- Different!
45653674
45653674
45653674
(NOTE: I've added "<---- Different!" to denote the unexpected value. You will not see this in the test results.)
As you can see, the result from the very first call to the GetParameters returns a different value than all subsequent calls.
I have had my nose in .NET for quite a while now, but have never seen anything quite like this. Is this expected behavior? Is there a preferred/known way of initializing the .NET type system so that this does not happen?
Finally, if anyone is interested, I ran into this problem while using xUnit with MEF 2, where a ParameterInfo being used as a key in a dictionary is not returning as equal to the ParameterInfo being passed in from a previously saved value. This, of course, results in unexpected behavior and resulting in failed tests when run concurrently.
EDIT: After some good feedback from the answers, I have (hopefully) clarified this question and scenario. The core of the issue is "Thread-Safety" of a "Thead-Safe" type, and acquiring better knowledge of what exactly this means.
ANSWER: This issue ended up being being due to several factors, one of which is due to me never-ending ignorance to multi-threaded scenarios, which it seems I am forever learning with no end for the foreseeable future. I am again appreciative of xUnit for being designed in such a way to learn this territory in such an effective manner.
The other issue does appear to be inconsistencies with how the .NET type system initializes. With the TypeInfo/Type, you get the same type/reference/hashcode no matter which thread accesses it however many times. For MemberInfo/MethodInfo/ParameterInfo, this is not the case. Thread access beware.
Finally, it seems I am not the only person with this confusion and this has indeed been recognized as an invalid assumption on a submitted issue to .NET Core's GitHub repository.
So, problem solved, mostly. I would like to send my thanks and appreciation to all involved in dealing with my ignorance in this matter, and helping me learn (what I am finding is) this very complex problem space.

It is one instance on the first call, and then another instance on every subsequent call.
OK, that's fine. A bit weird, but the method is not documented as always returning the same instance every time.
So, one thread will get one version on the first call, and then each thread will get another (unchanging instance on each subsequent call.
Again, weird, but perfectly legal.
Is this expected behavior?
Well, I would not have expected it before your experiment. But after your experiment, yes, I expect that behaviour to continue.
Is there a preferred/known way of initializing the .NET type system so that this does not happen?
Not to my knowledge.
If I am using that first call to store a key then yes, that is a problem.
Then you have evidence that you should stop doing that. If it hurts when you do that, don't do it.
A ParameterInfo reference should always represent the same ParameterInfo reference regardless of the thread it is on or how many times accessed.
That's a moral statement about how the feature should have been designed. It's not how it was designed, and its clearly not how it was implemented. You can certainly make the argument that the design is bad.
Mr. Lippert is also right in that the documentation does not guarantee/specify this, but this has always been my expectation of and experience with this behavior until this point.
Past performance is no guarantee of future results; your experience was not sufficiently varied until now. Multithreading has a way of confounding people's expectations! A world where memory is constantly changing unless something is keeping it still is contrary to our normal mode of things being the same until something changes them.

As an answer, I am looking at the .NET sources and the ConstructorInfo class has this in its bowels:
private ParameterInfo[] m_parameters = null; // Created lazily when GetParameters() is called.
That's their comment, not mine. Let's see GetParameters:
[System.Security.SecuritySafeCritical] // auto-generated
internal override ParameterInfo[] GetParametersNoCopy()
{
if (m_parameters == null)
m_parameters = RuntimeParameterInfo.GetParameters(this, this, Signature);
return m_parameters;
}
[Pure]
public override ParameterInfo[] GetParameters()
{
ParameterInfo[] parameters = GetParametersNoCopy();
if (parameters.Length == 0)
return parameters;
ParameterInfo[] ret = new ParameterInfo[parameters.Length];
Array.Copy(parameters, ret, parameters.Length);
return ret;
}
So no locking, nothing that would prevent the m_parameters being overridden by a racing thread.
Update: Here is the relevant code inside GetParameters: args[position] = new RuntimeParameterInfo(sig, scope, tkParamDef, position, attr, member); It is clear that in this case RuntimeParameterInfo is just a container for the parameters given in its constructor. There was never even the intention to get the same instance.
That is unlike TypeInfo, which is inheriting from Type and also implementing IReflectableType and which for its GetTypeInfo method just returns itself as an IReflectableType, so maintaining the same instance of the type.

Related

C# Closures and a self made SpinLock.RecursiveEnter

actually what I'm simply trying to achieve is to get to know multithreading in C#.
SO i have this class called WeakeningEvictionary{TKey, TValue}, which has a private Dictionary{TKey, CachedValue{TValue}} that functions as the cache. CachedValue is a Wrapper that has a Strong- and WeakReference to TValue. After a predefined Time a Task is created to nullify the StrongReference and put it into WeakReference. I also have a HashSet implemented that keeps track of which keyValuePairs to evict. (added to when weakening happened, removed from when SetValue is called) Immediately after GC has done its Job another Task is created to evict all those mentioned Pairs.
Actually I wouldn't need a RecursiveLock for this, but I encountered Issues, when some stored Information is asked recursively because a construction series required so.
So I came up with this code: (Updated, was a not-going-to-work ExtensionMethod before)
public void RecursiveEnter(Action action)
{
if (_spinLock.IsHeldByCurrentThread)
{
action();
}
else
{
bool gotLock = false;
_spinLock.Enter(ref gotLock);//blocking until acquired
action();
if (gotLock) _spinLock.Exit();
}
}
So what I'm trying to do now is:
private void Evict()
{
RecursiveEnter(() =>
{
foreach (TKey key in toEvict)
{
_dict.Remove(key);
}
}
);
}
Alright what if I use
And my Question is: What are the Risks? And are Closures known to cause Issues when being used by Threads in this way?
Thanks for your Input ;-)
Right off the bat, the method call is 100% not going to work: SpinLock is a value type, you must pass it by reference (RecursiveEnter(ref SpinLock spinLock, Action action)) and not by value.
See for example https://learn.microsoft.com/en-us/dotnet/api/system.threading.spinlock?view=netframework-4.7.2#remarks
I'm not sure this is the best thing for you to use: you should start with a higher-level primitive (maybe a ReaderWriterLockSlim) and refine things only with careful testing and understanding.

How to secure delegate instance reference

In the perspective of callbacks, I am facing a strange situation when I knew that myDelegate.Target contains the reference to the class whose method it contains. (I searched it on SO, however I excuse if I missed some thread already answering this)
For example
public delegate void TravePlanDelegate();
public class Traveller
{
//Papa is planing a tour, along with Mama
public void Planner()
{
//Asking me (delegate) to hold a letter about PlanA's detail
TravelPlanDelegate myPlan = PlanA;
//Sending me to TravelAgency office with letter
new TravelAgency().ExecuteTravelPlan(myPlan);
}
public void PlanA()
{
//Papa's open plan with Mama
Console.WriteLine("First Berline, then New Yark and finally Lahore");
}
public void PlanB()
{
//Papa's secret plan
Console.WriteLine("First Dubai, and then Lahore");
}
}
public class TravelAgency
{
public void ExecuteTravelPlan(TravePlanDelegate tp)
{
Traveller traveller = (Traveller)tp.Target;
//Here it should execute plan
//tp.Target - A reference to Traveler class, which can lead travel
//agency to Papa's secret plan (And exposes it to Mama)
}
}
In this example, TravelAgency can get information from delegate about papa's secret plan too. Did I get delegate concept properly or missing something?
Your assumption is correct. Unfortunately, however you try to "encapsulate" your object- there must always be a reference to it somewhere, otherwise it would be impossible to invoke it's instance method.
As some kind of counter measure, you can proxy the method invocation to a lambda expression:
TravelPlanDelegate myPlan = (args) =>PlanA(args);
This makes it less likely that any rogue code will attempt to carry out some ill intended operations on your code, since knowing how your code looks like in advance will not help it accomplish a thing.
Note that this does not ensure a thing, since the produced delegate still has a Target property to an object which holds a reference to yours.
Crackers which are smart enough can still apply reflection to the generated class and obtain a reference to your object.
Conclusion:
Only consume code you trust - it is not much of a problem in today's Open Source driven world.

Testing methods with overloading using shims and stubs in VS 2013 c# Code [duplicate]

What is the best way to unit test a method that doesn't return anything? Specifically in c#.
What I am really trying to test is a method that takes a log file and parses it for specific strings. The strings are then inserted into a database. Nothing that hasn't been done before but being VERY new to TDD I am wondering if it is possible to test this or is it something that doesn't really get tested.
If a method doesn't return anything, it's either one of the following
imperative - You're either asking the object to do something to itself.. e.g change state (without expecting any confirmation.. its assumed that it will be done)
informational - just notifying someone that something happened (without expecting action or response) respectively.
Imperative methods - you can verify if the task was actually performed. Verify if state change actually took place. e.g.
void DeductFromBalance( dAmount )
can be tested by verifying if the balance post this message is indeed less than the initial value by dAmount
Informational methods - are rare as a member of the public interface of the object... hence not normally unit-tested. However if you must, You can verify if the handling to be done on a notification takes place. e.g.
void OnAccountDebit( dAmount ) // emails account holder with info
can be tested by verifying if the email is being sent
Post more details about your actual method and people will be able to answer better.
Update: Your method is doing 2 things. I'd actually split it into two methods that can now be independently tested.
string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );
String[] can be easily verified by providing the first method with a dummy file and expected strings. The second one is slightly tricky.. you can either use a Mock (google or search stackoverflow on mocking frameworks) to mimic the DB or hit the actual DB and verify if the strings were inserted in the right location. Check this thread for some good books... I'd recomment Pragmatic Unit Testing if you're in a crunch.
In the code it would be used like
InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
Test its side-effects. This includes:
Does it throw any exceptions? (If it should, check that it does. If it shouldn't, try some corner cases which might if you're not careful - null arguments being the most obvious thing.)
Does it play nicely with its parameters? (If they're mutable, does it mutate them when it shouldn't and vice versa?)
Does it have the right effect on the state of the object/type you're calling it on?
Of course, there's a limit to how much you can test. You generally can't test with every possible input, for example. Test pragmatically - enough to give you confidence that your code is designed appropriately and implemented correctly, and enough to act as supplemental documentation for what a caller might expect.
As always: test what the method is supposed to do!
Should it change global state (uuh, code smell!) somewhere?
Should it call into an interface?
Should it throw an exception when called with the wrong parameters?
Should it throw no exception when called with the right parameters?
Should it ...?
Try this:
[TestMethod]
public void TestSomething()
{
try
{
YourMethodCall();
Assert.IsTrue(true);
}
catch {
Assert.IsTrue(false);
}
}
Void return types / Subroutines are old news. I haven't made a Void return type (Unless I was being extremely lazy) in like 8 years (From the time of this answer, so just a bit before this question was asked).
Instead of a method like:
public void SendEmailToCustomer()
Make a method that follows Microsoft's int.TryParse() paradigm:
public bool TrySendEmailToCustomer()
Maybe there isn't any information your method needs to return for usage in the long-run, but returning the state of the method after it performs its job is a huge use to the caller.
Also, bool isn't the only state type. There are a number of times when a previously-made Subroutine could actually return three or more different states (Good, Normal, Bad, etc). In those cases, you'd just use
public StateEnum TrySendEmailToCustomer()
However, while the Try-Paradigm somewhat answers this question on how to test a void return, there are other considerations too. For example, during/after a "TDD" cycle, you would be "Refactoring" and notice you are doing two things with your method... thus breaking the "Single Responsibility Principle." So that should be taken care of first. Second, you might have idenetified a dependency... you're touching "Persistent" Data.
If you are doing the data access stuff in the method-in-question, you need to refactor into an n-tier'd or n-layer'd architecture. But we can assume that when you say "The strings are then inserted into a database", you actually mean you're calling a business logic layer or something. Ya, we'll assume that.
When your object is instantiated, you now understand that your object has dependencies. This is when you need to decide if you are going to do Dependency Injection on the Object, or on the Method. That means your Constructor or the method-in-question needs a new Parameter:
public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)
Now that you can accept an interface of your business/data tier object, you can mock it out during Unit Tests and have no dependencies or fear of "Accidental" integration testing.
So in your live code, you pass in a REAL IBusinessDataEtc object. But in your Unit Testing, you pass in a MOCK IBusinessDataEtc object. In that Mock, you can include Non-Interface Properties like int XMethodWasCalledCount or something whose state(s) are updated when the interface methods are called.
So your Unit Test will go through your Method(s)-In-Question, perform whatever logic they have, and call one or two, or a selected set of methods in your IBusinessDataEtc object. When you do your Assertions at the end of your Unit Test you have a couple of things to test now.
The State of the "Subroutine" which is now a Try-Paradigm method.
The State of your Mock IBusinessDataEtc object.
For more information on Dependency Injection ideas on the Construction-level... as they pertain to Unit Testing... look into Builder design patterns. It adds one more interface and class for each current interface/class you have, but they are very tiny and provide HUGE functionality increases for better Unit-Testing.
You can even try it this way:
[TestMethod]
public void ReadFiles()
{
try
{
Read();
return; // indicates success
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
}
it will have some effect on an object.... query for the result of the effect. If it has no visible effect its not worth unit testing!
Presumably the method does something, and doesn't simply return?
Assuming this is the case, then:
If it modifies the state of it's owner object, then you should test that the state changed correctly.
If it takes in some object as a parameter and modifies that object, then your should test the object is correctly modified.
If it throws exceptions is certain cases, test that those exceptions are correctly thrown.
If its behaviour varies based on the state of its own object, or some other object, preset the state and test the method has the correct Ithrough one of the three test methods above).
If youy let us know what the method does, I could be more specific.
Use Rhino Mocks to set what calls, actions and exceptions might be expected. Assuming you can mock or stub out parts of your method. Hard to know without knowing some specifics here about the method, or even context.
Depends on what it's doing. If it has parameters, pass in mocks that you could ask later on if they have been called with the right set of parameters.
What ever instance you are using to call the void method , You can just use ,Verfiy
For Example:
In My case its _Log is the instance and LogMessage is the method to be tested:
try
{
this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure");
}
Catch
{
Assert.IsFalse(ex is Moq.MockException);
}
Is the Verify throws an exception due to failure of the method the test would Fail ?

Moq Error: Cannot cast 'AnObject' to 'System.Delegate'

I have been trying to get past this problem for a couple of days now to no avail. I am trying to test the functionality of AnObject.AnAction (preemptive apologies, I have to obfuscate class/method names.) My goal is to keep MyTestObj.do_work(AnObject) from actually doing anything when it is called. It has code that I do want to be called in a unit test environment.
Here is my Unit test code:
Mock< MyTestObj > myTestObj_mock = new Mock< MyTestObj > ();
myTestObj_mock.Setup( e => e.do_work( It.IsAny< AnObject > () ) );
...
AnObject tester = new AnObject();
tester.anAction( myTestObj_mock.Object );
within the method AnObject.AnAction( MyTestObj mto ):
...
mto.do_work( this );
...
It is at this point when ran that I get this error:
System.InvalidCastException : Unable to cast object of type
'myNamespace.AnObject' to type 'System.Delegate'.
MyTestObj.do_work is a virtual method.
I have absolutely no idea why this error is coming up. I've stepped through the code as NUnit ran it and I am certain that is the point in which it crashes. It will not go any further into the code.
I'm really stumped. Does anybody have any idea what is going on?
Thanks in advance!
***Updates***
I tried to create an instance of AnObject within AnObject.AnAction and pass it instead of 'this':
...
AnObject test = new AnObject();
mto.do_work( test );
...
This did not have any effect.
As your question is written you do not need to setup the myTestObj_mock.do_work().
Setup is used to say, when method X is called return value Y. Or alternativly that when method X is called, exception Z is returned. Ask yourself is that really what I need to do?
Here you aren't returning anything from the method:
mto.do_work( this );
Also, here:
myTestObj_mock.Setup( e => e.do_work( It.IsAny< AnObject > () ) );
You aren't defining any Return for your setup.
You should be able to supply a mock myTestObj_mock without defining the setup in this case. Just remove the line with the Setup and run the test again.
A guess:
If you defined the Setup because you wanted your test to make sure AnObject.AnAction really calls the do_work method, what you need to do is define a Verify method rather than a Setup, likewise:
mock.Verify(foo => foo.Execute("ping"));
or in your case something like
myTestObj_mock.Verify(m => m.do_work(It.IsAny< AnObject > ()), Times.AtLeastOnce());
Another guess:
If you defined the mock because you pass a "this" reference and expect do_work to modify some parameters of "this" for the test to pass then you shouldn't be mocking here. Remember that mocks aren't really instances of your objects, so the code that modify the this reference will never get called.
I was finally able to get to a compiler and play with the code and here is what I found. It is basically what Giles said above for his first part of the question.
Here is the code hint for Setup:
Specifies a setup on the mocked type for a call to a value returning method.
And, here is the actual code for Setup
public ISetup<T> Setup(Expression<Action<T>> expression)
So, Setup is actually setting up the code as an Action (a delegate, basically). When the test runner is run, it hits this point and usually expects to feed the delegate to the Returns method
public IReturnsResult<TMock> Returns(TResult value)
So, this is never done, and instead of Mock running through the whole expected path and negotiating all of the code out, then it returns mistyped values.
Sooo, this is basically where Giles explanation is correct. If you are testing that the do_work method is being called, then you want to use Verify (which truly uses your fake object as a mock). However, if not, then you have no need to even set this up as it does nothing. If that is the case, then maybe that piece of code should not be in that specific code block, but you would be best to evaluate that.
And, finally, the Setup method should only be used if you are truly using your object as a stub, simply using it to inject logic into your code.
Hopefully, that makes sense and helps you with your problem.
Also, a Callback might be of use here depending on what you are doing. But, I am not sure. They have many examples in the Moq quickstart
UPDATE FOR MY ATTEMPT AT RECREATING using Version 4.0.10827...and had no issues
[Test]
public void teststuff()
{
Mock<MyTestObj> myTestObj_mock = new Mock<MyTestObj>();
myTestObj_mock.Setup(e => e.do_work(It.IsAny<AnObject>()));
AnObject tester = new AnObject();
tester.anAction(myTestObj_mock.Object);
}
...
public class MyTestObj
{
public virtual void do_work(AnObject o)
{
}
}
public class AnObject
{
public void anAction(MyTestObj obj)
{
obj.do_work(new AnObject());
}
}

Passing a lambda to a secondary AppDomain as a stream of IL and assembling it back using DynamicMethod

Is it possible to pass a lambda expression to a secondary AppDomain as a stream of IL bytes and then assemble it back there using DynamicMethod so it can be called?
I'm not too sure this is the right way to go in the first place, so here's the (detailed) reason I ask this question...
In my applications, there are a lot of cases when I need to load a couple of assemblies for reflection, so I can determine what to do with them next. The problem part is I need to be able to unload the assemblies after I'm finished reflecting over them. This means I need to load them using another AppDomain.
Now, most of my cases are sort of similar, except not quite. For example, sometimes I need to return a simple confirmation, other times I need to serialize a resource stream from the assembly, and again other times I need to make a callback or two.
So I end up writing the same semi-complicated temporary AppDomain creation code over and over again and implementing custom MarshalByRefObject proxies to communicate between the new domain and the original one.
As this is not really acceptable anymore, I decided to code me an AssemblyReflector class that could be used this way:
using (var reflector = new AssemblyReflector(#"C:\MyAssembly.dll"))
{
bool isMyAssembly = reflector.Execute(assembly =>
{
return assembly.GetType("MyAssembly.MyType") != null;
});
}
AssemblyReflector would automize the AppDomain unloading by virtue of IDisposable, and allow me to execute a Func<Assembly,object>-type lambda holding the reflection code in another AppDomain transparently.
The problem is, lambdas cannot be passed to other domains so simply. So after searching around, I found what looks like a way to do just that: pass the lambda to the new AppDomain as an IL stream - and that brings me to the original question.
Here's what I tried, but didn't work (the problem was BadImageFormatException being thrown when trying to call the new delegate):
public delegate object AssemblyReflectorDelegate(Assembly reflectedAssembly);
public class AssemblyReflector : IDisposable
{
private AppDomain _domain;
private string _assemblyFile;
public AssemblyReflector(string fileName) { ... }
public void Dispose() { ... }
public object Execute(AssemblyReflectorDelegate reflector)
{
var body = reflector.Method.GetMethodBody();
_domain.SetData("IL", body.GetILAsByteArray());
_domain.SetData("MaxStackSize", body.MaxStackSize);
_domain.SetData("FileName", _assemblyFile);
_domain.DoCallBack(() =>
{
var il = (byte[])AppDomain.CurrentDomain.GetData("IL");
var stack = (int)AppDomain.CurrentDomain.GetData("MaxStackSize");
var fileName = (string)AppDomain.CurrentDomain.GetData("FileName");
var args = Assembly.ReflectionOnlyLoadFrom(fileName);
var pars = new Type[] { typeof(Assembly) };
var dm = new DynamicMethod("", typeof(object), pars,
typeof(string).Module);
dm.GetDynamicILInfo().SetCode(il, stack);
var clone = (AssemblyReflectorDelegate)dm.CreateDelegate(
typeof(AssemblyReflectorDelegate));
var result = clone(args); // <-- BadImageFormatException thrown.
AppDomain.CurrentDomain.SetData("Result", result);
});
// Result obviously needs to be serializable for this to work.
return _domain.GetData("Result");
}
}
Am I even close (what's missing?), or is this a pointless excercise all in all?
NOTE: I realize that if this worked, I'd still have to be carefull about what I put into lambda in regard to references. That's not a problem, though.
UPDATE: I managed to get a little further. It seems that simply calling SetCode(...) is not nearly enough to reconstruct the method. Here's what's needed:
// Build a method signature. Since we know which delegate this is, this simply
// means adding its argument types together.
var builder = SignatureHelper.GetLocalVarSigHelper();
builder.AddArgument(typeof(Assembly), false);
var signature = builder.GetSignature();
// This is the tricky part... See explanation below.
di.SetCode(ILTokenResolver.Resolve(il, di, module), stack);
dm.InitLocals = initLocals; // Value gotten from original method's MethodInfo.
di.SetLocalSignature(signature);
The trick is as follows. Original IL contains certain metadata tokens which are valid only in the context of the original method. I needed to parse the IL and replace those tokens with ones that are valid in the new context. I did this by using a special class, ILTokenResolver, which I adapted from these two sources: Drew Wilson and Haibo Luo.
There is still a small problem with this - the new IL doesn't seem to be exactly valid. Depending on the exact contents of the lambda, it may or may not throw an InvalidProgramException at runtime.
As a simple example, this works:
reflector.Execute(a => { return 5; });
while this doesn't:
reflector.Execute(a => { int a = 5; return a; });
There are also more complex examples that are either working or not, depending on some yet-to-be-determined difference. It could be I missed some small but important detail. But I'm reasonably confident I'll find it after a more detailed comparison of the ildasm outputs. I'll post my findings here, when I do.
EDIT: Oh, man. I completely forgot this question was still open. But as it probably became obvious in itself, I gave up on solving this. I'm not happy about it, that's for sure. It's really a shame, but I guess I'll wait for better support from the framework and/or CLR before I attempt this again. There're just to many hacks one has to do to make this work, and even then it's not reliable. Apologies to everyone interested.
I didn't get exactly what is the problem you are trying to solve, but I made a component in the past that may solve it.
Basically, its purpose was to generate a Lambda Expression from a string. It uses a separate AppDomain to run the CodeDOM compiler. The IL of a compiled method is serialized to the original AppDomain, and then rebuild to a delegate with DynamicMethod. Then, the delegate is called and an lambda expression is returned.
I posted a full explanation of it on my blog. Naturally, it's open source. So, if you get to use it, please send me any feedback you think is reasonable.
Probably not, because a lambda is more than just an expression in source code. lambda expressions also create closures which capture/hoist variables into their own hidden classes. The program is modified by the compiler so everywhere you use those variables you're actually talking to the class. So you'd have to not only pass the code for the lambda, but also any changes to closure variables over time.

Categories

Resources