I've done this before, so I know it can be done..(although badly documented) but forgot how. I've been searching for 2 hours now and can't find anything like it.
I want to push and pull values on the callstack, like so:
public void Method1()
{
InsertMagicClassHere.Push("Key", 1);//or something
Method2();
}
public void Method2()
{
int value = InsertMagicClassHere.Pull("Key");//or something
}
I need this parameter in nearly all my methods for logging.. and don't want to pass this 3 layers deep with arguments.
You are looking for Reflection.Emit; however, this is not how it works.
You can't really emit inline opcodes.
Instead, you can emit whole methods/classes and load them as 'temporary' assemblies. You then call into the emitted method.
Obligatory sample:
public void CreateMethod()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
AssemblyBuilder asmbuilder = this.GetAssemblyBuilder("MyAssembly");
ModuleBuilder mbuilder = this.GetModule(asmbuilder);
TypeBuilder tbuilder = this.GetTypeBuilder(mbuilder, "MyClass");
Type[] tparams = { typeof(System.Int32), typeof(System.Int32) };
MethodBuilder methodSum = this.GetMethod(tbuilder, "Sum", typeof(System.Single),
tparams);
ILGenerator generator = methodSum.GetILGenerator();
generator.DeclareLocal(typeof(System.Single));
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldarg_2);
generator.Emit(OpCodes.Add_Ovf);
generator.Emit(OpCodes.Conv_R4);
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ret);
}
So what you could do
take an existing method
disassemble it
write the code to emit a new method on the IL level (using Reflection.Emit)
load the emitted assembly
call into your code.
See these articles for good starters:
http://www.codeproject.com/KB/cs/DLR.aspx
MSDN: using Reflection Emit
Okay. the answer is:
CallContext
This works:
public void Method1()
{
CallContext.SetData("Key", 1);
Method2();
}
public void Method2()
{
int value = (int)CallContext.GetData("Key");
}
Like I said this is not a well known feature.. If you knew it, you would have known what I was referring to.
I think it's a cool feature, not many uses for it, but still..
Related
I'm generating a random number from 1-1000. I have 200 functions named function1, function4, function 10, function 11, etc. What I would like to do is execute a specific function depending on if the number generated requires a function, and ignore it if not.
My first thought was to create an int[] containing all of the values that would trigger a function, and if the int[] contains the random number to use if statements to figure out what the number is. I'm concerned that it must be a really crude solution to an easy problem though.
I know the "best way" to do something is subjective, but is there a better way to accomplish this?
UPDATE: As per comments, I should probably have started out by pointing out that doing this for 200 functions is probably a good sign that there is some serious issue in your design. This is probably an XY question where you are trying to solve a problem in some crazy way and asking about your intended solution instead of asking about the problem itself.
That said I'll leave the original answer because it's still good advice when mapping a reasonable amount of function calls that can/will change during the life cylce of your app or dynamically as the code runs.
I won't get into why you are doing this, but I'll try to at least point you in the right direction so this doesn't become a complete nightmare when you need to modify/expand behavior:
You can map numbers to function calls using delegates and a dictionary. Assuming your functions take no arguments and return void you'd do:
var functionsMap = new Dictionary<int, Action>();
//map functions
var r = getSomeRandomNumber();
if (functions.TryGetValue(r), out var a)
a(); //invoke function
Mapping functions is simply adding keys and values:
functionsMap.Add(1, () => function1());
functionsMap.Add(3, () => function3());
//etc.
If your functions take arguments or return values, you'd use the adequate delegate: Action<T>, Func<T1, T2> etc.
You can use reflection to invoke appropriate method:
Type exampleType = exampleObject.GetType();
MethodInfo exampleMethod = exampleType.GetMethod(methodName);
exampleMethod.Invoke(this, null);
Where methodName can be created using your random number.
Without commenting on the wisdom of having 200 functions named the way yours are, you can use reflection to determine whether a given functionX() exists, like so:
public void ExecuteDynamicMethod(int number)
{
// Modify these two lines with your app's dll/exe and class type:
Assembly assembly = Assembly.LoadFile("...Assembly1.dll");
Type type = assembly.GetType("YourClassType");
if (type != null)
{
MethodInfo methodInfo = type.GetMethod("function" + number);
if (methodInfo != null)
{
object classInstance = Activator.CreateInstance(type, null);
methodInfo.Invoke(classInstance, null); // null = "no function arguments"
}
}
}
This can then be called for a given value like
ExecuteDynamicMethod(14);
See this SO answer for the inspiration behind this.
Reflection can be used for this purpose. I want to give and keep below example for not only the objective of the question but also for future reference. Also, of course that many function is not good but below code shows the approach that can work with many functions if they have similar name (like starting with "function" keyword).
Assume below is Methods.cs
using System;
using System.Reflection;
namespace YourMethodNamespace
{
public class YourMethodClass
{
public void function1()
{
Console.WriteLine("Function-1");
}
public void function2()
{
Console.WriteLine("Function-2");
}
...
public void function200()
{
Console.WriteLine("Function-200");
}
public static void invokeMethodsDynamically(int randomNumber){
Type yourClassType = typeof(YourMethodClass);
ConstructorInfo yourClassConstructorInfo = yourClassType.GetConstructor(Type.EmptyTypes);
object yourClassObject = yourClassConstructorInfo.Invoke(new object[]{});
//If the constructor has parameters, then we can pass them by this way. Like below;
/*ConstructorInfo yourClassConstructorInfo = yourClassType.GetConstructor(new[]{typeof(int)});
object yourClassObject = yourClassConstructorInfo.Invoke(new object[]{3});
*/
MethodInfo[] methodInfoArr = yourClassType.GetMethods();
foreach(MethodInfo methodInfo in methodInfoArr){
if(methodInfo.Name == "function" + randomNumber){
methodInfo.Invoke(yourClassObject, null);
}
}
}
}
}
Let's say below is Program.cs
using System;
using YourMethodNamespace;
namespace YourProgramNamespace
{
public class YourProgramClass
{
public static void Main()
{
Random random = new Random();
int randomNumber = random.Next(1, 201);
//If Methods.cs is in another Assembly
/*string pathToDllAssembly = #"Domain.dll";
Assembly dllAssembly = Assembly.LoadFrom(pathToDllAssembly);
Type methodsClassType = dllAssembly.GetType("YourMethodNamespace.YourMethodClass");
ConstructorInfo methodClassConstructorInfo = methodsClassType.GetConstructor(Type.EmptyTypes);
object methodsClassObject = methodClassConstructorInfo.Invoke(new object[]{});
MethodInfo methodInfo = methodsClassType.GetMethod("invokeMethodsDynamically");
methodInfo.Invoke(methodsClassObject, new object[]{randomNumber});
*/
YourMethodClass.invokeMethodsDynamically(randomNumber, null);
}
}
}
Also for testing and observing, below link can be used.
https://repl.it/#erdsavasci/ReflectionTest
During some experiments with IL, I attempted to change callvirt calls in an assembly to call methods. Basically what happens is that I have an inheritance chain with member functions that I am calling.
Basically the call is similar to this:
((MyDerivedClass)myBaseObject).SomeCall();
or in IL
castclass MyDerivedClass // ** 1
call SomeCall() // ** 2
The base class defines SomeCall as abstract method, the derived class implements it. The derived class is sealed.
I know that callvirt is basically the equivalent of check if the object is null, if it's not call the method using the vtable and if it is, throw an exception. In my case I know that it's never null and I know that's the implementation I want to call. I understand why you would normally need a callvirt in such a case.
That said, because I know that the object is never null, and always is an instance of the derived type, I would think it's not a problem:
When you consider that data and types are separated, I'd actually figure that (**1) could be removed (the data of the object will be the same) and
That (**2) can be a simple call, since we know exactly what member to call. No vtable lookup is necessary.
It also seemed to me like a quite reasonable thing the compiler can also deduce in some cases. For those interested, yes, there is a speed penalty for callvirt, although it's pretty small.
However. PEVerify tells me it's wrong. And as a good boy, I always take note of what PEVerify is telling me. So what am I missing here? Why does changing this call lead to an incorrect assembly?
Apparently creating a minimum test case isn't so simple... so far I don't have a lot of luck with it.
As for the issue itself, I can simply reproduce it in a larger program:
[IL]: Error: [C:\tmp\emit\test.dll : NubiloSoft.Test::Value][offset 0x00000007] The 'this' parameter to the call must be the calling method's 'this' parameter.
IL code of Value:
L_0000: ldarg.0
L_0001: ldfld class NubiloSoft.Test SomeField
L_0006: ldarg.1
L_0007: call instance bool NubiloSoft.Test::Contains(int32)
The type of the field is NubiloSoft.Test.
As for Contains, it's abstract in a base class, and in the derived class it's overridden. Just as you would expect. When I remove the 'abstract base method' + 'override', PEVerify likes it all again.
In an attempt to reproduce the issue I did this, so far without luck to reproduce it in a minimal test case:
public abstract class FooBase
{
public abstract void MyMethod();
}
// sealed doesn't seem to do anything...
public class FooDerived : FooBase
{
public override void MyMethod()
{
Console.WriteLine("Hello world!");
}
}
public class FooGenerator
{
static void Main(string[] args)
{
Type t = CreateClass();
object o = Activator.CreateInstance(t, new[] { new FooDerived() });
var meth = t.GetMethod("Caller");
meth.Invoke(o, new object[0]);
Console.ReadLine();
}
public static Type CreateClass()
{
// Create assembly
var assemblyName = new AssemblyName("testemit");
var assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndSave, #"c:\tmp");
// Create module
var moduleBuilder = assemblyBuilder.DefineDynamicModule("testemit", "test_emit.dll", false);
// Create type : IFoo
var typeBuilder = moduleBuilder.DefineType("TestClass", TypeAttributes.Public, typeof(object));
// Apparently we need a field to trigger the issue???
var field = typeBuilder.DefineField("MyObject", typeof(FooDerived), FieldAttributes.Public);
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.HideBySig |
MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.HasThis, new Type[] { typeof(FooDerived) });
// Generate the constructor IL.
ILGenerator gen = constructorBuilder.GetILGenerator();
// The constructor calls the constructor of Object
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
// Store the field
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Stfld, field);
// Return
gen.Emit(OpCodes.Ret);
// Add the 'Second' method
var mb = typeBuilder.DefineMethod("Caller",
MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual |
MethodAttributes.Final | MethodAttributes.Public, CallingConventions.HasThis,
typeof(void), Type.EmptyTypes);
// Implement
gen = mb.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldfld, field);
gen.Emit(OpCodes.Call, typeof(FooDerived).GetMethod("MyMethod"));
gen.Emit(OpCodes.Ret);
Type result = typeBuilder.CreateType();
assemblyBuilder.Save("testemit.dll");
return result;
}
}
When you run it and call peverify, it'll tell you the code doesn't have bugs... :-S
I'm not sure what's going on here... seems to me like it's pretty similar.
I suspect this blog post is relevant. In particular:
Some consider this a violation of privacy through inheritence. Lots of code is written under the assumption that overriding a virtual method is sufficient to guarantee custom logic within gets called. Intuitively, this makes sense, and C# lulls you into this sense of security because it always emits calls to virtual methods as callvirts.
And then:
Late in Whidbey, some folks decided this is subtly strange enough that we at least don’t want partially trusted code to be doing it. That it’s even possible is often surprising to people. We resolved the mismatch between expectations and reality through the introduction of a new verification rule.
The rule restricts the manner in which callers can make non-virtual calls to virtual methods, specifically by only permitting it if the target method is being called on the caller’s ‘this’ pointer. This effectively allows an object to call up (or down, although that would be odd) its own type hierarchy.
In other words, assuming this change is what you're talking about (it sounds like it) the rule is there to prevent IL from violating normal expectations of how virtual methods are called.
You might want to try making the SomeCall method sealed in MyDerivedClass... at that point it's not virtual any more in the sense that a call to SomeCall on a reference of type MyDerivedClass will always call the same method... whether that's sufficiently non-virtual for peverify is a different matter though :)
I'm trying to figure out what the limitations really means when deploying for iOS from Xamarin.
http://developer.xamarin.com/guides/ios/advanced_topics/limitations/
I was under the impression that you have no JIT and thus any MakeGenericMethod or MakeGenericType would NOT work as that would require JIT compilation.
Also I understood that when running on the simulator, these restrictions does not apply since the simulator is not running in the full AOT (Ahead of Time) mode.
After setting up my Mac so that I could deploy to my phone, I would except the following test to fail when running on the actual device (iPhone).
[Test]
public void InvokeGenericMethod()
{
var method = typeof(SampleTests).GetMethod ("SomeGenericMethod");
var closedMethod = method.MakeGenericMethod (GetTypeArgument());
closedMethod.Invoke (null, new object[]{42});
}
public static void SomeGenericMethod<T>(T value)
{
}
private Type GetTypeArgument()
{
return typeof(int);
}
The thing is that completes successfully and I can't really understand why. Does not this code require JIT compilation?
In an effort to "make it break" , I also did a test with MakeGenericType.
[Test]
public void InvokeGenericType()
{
var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));
var instance = Activator.CreateInstance (type);
var method = type.GetMethod ("Execute");
method.Invoke (instance, new object[]{"Test"});
}
public class SomeGenericClass<T>
{
public void Execute(T value)
{
}
}
How can this work when there is no JIT?
Am I missing something ?
In order to make the code fail go to iOS project options, tab "iOS Build" and change the "Linker Behavior:" to "Link all assemblies". Running the code will result in Exception and it will be of type default constructor for type XXX was not found.
Now, make a reference to the SomeGenericClass{string} in your code and the method will run just fine. The two added lines cause the compiler to include SomeGenericClass{string} in the binary. Note that the lines can be anywhere in the application that is compiled into the binary, they don't have to be in the same function.
public void InvokeGenericType()
{
// comment out the two lines below to make the code fail
var strClass = new SomeGenericClass<string>();
strClass.Execute("Test");
var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));
var instance = Activator.CreateInstance (type);
var method = type.GetMethod ("Execute");
method.Invoke (instance, new object[]{"Test"});
}
I have the following method:
public void DoSomething()
{
Console.WriteLine("");
}
I want to modify this code with Mono Cecil. I want to create an instance of a custom class within the method:
public void DoSomething()
{
MyClass instance = new MyClass();
Console.WriteLine("");
}
Currently I use the following code:
var constructorInfo = typeof(MyClass).GetConstructor(new Type[] { });
MethodReference myClassConstructor = targetAssembly.MainModule.Import(constructorInfo);
var processor = targetMethod.Body.GetILProcessor();
var firstInstruction = targetMethod.Body.Instructions[1];
var instructions = new List<Instruction>() {
processor.Create(OpCodes.Newobj, myClassConstructor),
processor.Create(OpCodes.Stloc_0)
};
foreach (var instruction in instructions)
{
processor.InsertBefore(firstInstruction, instruction);
}
After applying those changes, the program is invalid and cannot be executed.
If i use 'IL DASM' to look at the generated code the following statement is missing:
.locals init ([0] class [MyAssembly]MyNamespace.MyClass instance)
The rest of the IL is the same, as if I directly compile the full code.
Any ideas what I am doing wrong?
I have not tried it but by looking at the Cecil Source Code you should first create the local variable which is part of your MethodBody.
MethodBody has a Variables collection which can be filled via
body.Variables.Add( new VariableDefinition(typedef) )
Then you need to call processor.Create(xxx,indexto local variable);
That should do the trick. The only thing I did not see yet how you can get a TypeDefinition out from a Type. I think you need to load the assembly into Mono Cecil first before you can use this approach.
I'm trying to create an extension method using CodeDOM. There doesn't seem to be any support for them and using ExtensionAttribute (which C# uses internally to mark extension methods) is not allowed.
It's possible to use a trick to specify the this modifier, but how do I make the containing class static, so that the code actually compiles?
Since static is a C# concept, it's not exposed through the CodeDOM API. And setting TypeAttributes to TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Public doesn't work, because
an abstract class cannot be sealed or static
How do I make the extension method to compile?
I'm pretty sure you're looking for:
var staticClass = new CodeTypeDeclaration("Extensions")
{
Attributes = MemberAttributes.Public|MemberAttributes.Static
};
However, this appears not to work. Interestingly enough:
provider.Supports(GeneratorSupport.StaticConstructors);
// True
provider.Supports(GeneratorSupport.PublicStaticMembers);
// True
But yet when you go and output it, no changes even though the Attributes property clearly changes from 0x00005002 to 0x00006003.
Per Microsoft Connect this is not possible:
Thanks for reporting this. Unfortunately, it doesn't look like we can support static classes for CodeDom.
The reason is that one of the design goals of CodeDom is to be language-independent, so that any code generated for one language can easily be generated for a different language. While static classes are used often in C#, VB does not support them. Therefore, adding support for static classes will mean that some code that can compile for C# won't be compilable for VB, which goes against our goals.
While we can't act on this issue, we ask that you please continue to provide feedback in the future to help us improve.
A dirty workaround:
var type = new CodeTypeDeclaration("Extensions");
type.Attributes = MemberAttributes.Public;
type.StartDirectives.Add(
new CodeRegionDirective(CodeRegionMode.Start, "\nstatic"));
type.EndDirectives.Add(
new CodeRegionDirective(CodeRegionMode.End, String.Empty));
Produces:
#region
static
public class Extensions
{
}
#endregion
Which compiles.
Instead of compiling the CodeCompileUnit directly, you could get the source code, replace class Extensions with static class Extensions and compile that code.
Cleaned up the hack provided by sixlettervariables a little: placed it into a static method, as mentioned in the discussion.
public static void MarkAsStaticClassWithExtensionMethods(this CodeTypeDeclaration class_)
{
class_.Attributes = MemberAttributes.Public;
class_.StartDirectives.Add(new CodeRegionDirective(
CodeRegionMode.Start, Environment.NewLine + "\tstatic"));
class_.EndDirectives.Add(new CodeRegionDirective(
CodeRegionMode.End, string.Empty));
}
You can get your code to compile exactly how your want it by converting it directly into a string, and then hacking it:
private static CodeSnippetTypeMember CreateStaticClass(CodeTypeDeclaration type)
{
var provider = CodeDomProvider.CreateProvider("CSharp");
using (var sourceWriter = new StringWriter())
using (var tabbedWriter = new IndentedTextWriter(sourceWriter, "\t"))
{
tabbedWriter.Indent = 2;
provider.GenerateCodeFromType(type, tabbedWriter, new CodeGeneratorOptions()
{
BracingStyle = "C",
IndentString = "\t"
});
return new CodeSnippetTypeMember("\t\t" + sourceWriter.ToString().Replace("public class", "public static class"));
}
}