How can I convert C# methods to compiled expressions? - c#

I have the following class hierarchy:
public class Parent
{
[DebuggerStepThrough]
public void SayParent()
{
Console.WriteLine("Parent");
}
}
public sealed class Child : Parent
{
private static int _number = 0;
public Child() // May contain parameter i.e. not always parameterless consctructor
{
_number++;
}
[DebuggerStepThrough]
public void SayInstance()
{
Console.WriteLine("{0}-Say", _number);
}
[DebuggerStepThrough]
public void SayInstanceWithArg(string input)
{
Console.WriteLine("{0}-Say: {1}", _number, input);
}
[DebuggerStepThrough]
public static void SayStatic()
{
Console.WriteLine("{0}-Say", _number);
}
[DebuggerStepThrough]
public static void SayStaticWithArg(string input)
{
Console.WriteLine("{0}-Say: {1}", _number, input);
}
[DebuggerStepThrough]
public static Task SayStaticWithArgAndReturn(string input)
{
Console.WriteLine("{0}-Say: {1}", _number, input);
return null;
}
}
I need to be able to invoke any of these methods for a new instance of Child at any given time using reflection however to improve performance I need to resort to Delegate and/or Compiled Expressions.
So for example I can have:
var instanceOne = new Child();
var instanceTwo = new Child();
for which I would need to at runtime invoke these methods passing the arguments for those that need it. Note they include both static and instance methods with some accepting a parameter.
I have so far tried the following for the "SayInstance" method:
var sayInstanceMethod = typeof(Child)
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.Where(m => m.GetCustomAttributes(typeof(DebuggerStepThroughAttribute), true).Length > 0)
.Where(t => t.Name == "SayInstance")
.First()
And then:
var instance = Expression.Constant(new Child()); // This should NOT be Constant, but then what should it be?!
var mCallInstance = Expression.Call(instance, sayInstanceMethod);
Action action = Expression.Lambda<Action>(mCallInstance).Compile();
action();
action(); // I need to pass in a new instance of Child to this method somehow
However I am getting:
1-Say
1-Say
instead of:
1-Say
2-Say
I suspect this is due to Expression.Constant but I cannot figure out how I could let it accept an instance of Child as its target at runtime.
I am hopeless when it comes to Expressions :-(
I am basically trying to implement what Jon Skeet mentions HERE either using Delegates or Compiled Expressions.
Any help is very much appreciated.

If I understood correctly, you need to use parameters, like this:
var instanceOne = new Child();
var instanceTwo = new Child();
var instance = Expression.Parameter(typeof(Child), "c"); // This should NOT be Constant, but then what should it be?!
var mCallInstance = Expression.Call(instance, sayInstanceMethod);
Action<Child> action = Expression.Lambda<Action<Child>>(mCallInstance, instance).Compile();
action(instanceOne);
action(instanceTwo); // I need to pass in a new instance of Child to this method somehow
Of course this will not output 1, 2 because your _number field is static and after creation of two instances has value 2 for both.
EDIT. If you need to call method with arguments - declare more parameters. For example if SayInstance has one argument of type string, then:
var instanceOne = new Child();
var instanceTwo = new Child();
var instance = Expression.Parameter(typeof(Child), "instance");
var arg = Expression.Parameter(typeof(string), "arg");
var mCallInstance = Expression.Call(instance, sayInstanceMethod, arg);
Action<Child,string> action = Expression.Lambda<Action<Child,string>>(mCallInstance, instance, arg).Compile();
action(instanceOne, "one");
action(instanceTwo, "two");

Try this out, this workf for me for a parameterless constructor, but this is that you need:
var instance = Expression.New(typeof(Child).GetConstructor(new Type[0]));
var mCallInstance = Expression.Call(instance, sayInstanceMethod);
Action action = Expression.Lambda<Action>(mCallInstance).Compile();
action();
action(); // I need to pass in a new instance of Child to this method someh

Related

Get name of generic method inside a proxy class

I would like to create a proxy class that will be able to retrieve the name of a method given in argument, and an instance of a paramater with generic completion (aka I don't want nameof() or magic strings).
For example, I would like to be able to do something like
public interface ITestInterface
{
void TestMethod(Param myParam)
}
var proxy = new Proxy<ITestInterface>();
var param = new Param();
proxy.WriteName(x => ITestInterface.TestMethod(param));
and the proxy class be able to retrive the name of the method and do a tostring on the instance of the parameter :
public class Proxy<T>
{
public void WriteName(Something something)
{
Console.WriteLine(something.MethodName); // write "TestMethod"
Console.WriteLine(something.Parameter.ToString()); // use the tostring of the instance object
}
}
Thanks for your help
I would say it would not be easy to support all possible scenarios but for what you have described in the question you can try using expression trees:
public class Proxy<T>
{
public void WriteName(Expression<Action<T>> something)
{
// TODO: add correct handling for not supported operations
if (something.Body is MethodCallExpression mc)
{
Console.WriteLine(mc.Method.Name);
foreach (var arg in mc.Arguments)
{
if (arg is MemberExpression me && me.Expression is ConstantExpression cnst)
{
var val = me.Member.MemberType switch
{
MemberTypes.Field => ((FieldInfo)me.Member).GetValue(cnst.Value),
MemberTypes.Property => ((PropertyInfo)me.Member).GetValue(cnst.Value),
_ => null
};
Console.WriteLine(val);
}
}
}
}
}
And usage:
var proxy = new Proxy<ITestInterface>();
var param = new Param();
proxy.WriteName(t => t.TestMethod(param)); // actually many more can be passed here
If I understand correctly you can try this:
public class Proxy<T>
{
public void WriteName(Expression<Action> action)
{
var methodCallExp = (MethodCallExpression)action.Body;
Console.WriteLine(methodCallExp.Arguments.First().ToString());
Console.WriteLine(methodCallExp.Method.Name);
}
}
and call proxy class like this:
var proxy = new Proxy<ITestInterface>();
proxy.WriteName(() => new ConcreteTestInterface().TestMethod(param));

How to create lambdas and add them to actions using reflection

Suppose in C# I have class that has an arbitrary number of Actions, which can have any number of generic arguments:
public class Container
{
public Action a;
public Action<float> b;
public Action<int, float> c;
// etc...
}
And I am registering some debug lambdas on an instance of this class which just print out the name of the action's field:
public static void Main()
{
Container container = new Container();
container.a += () => Console.WriteLine("a was called");
container.b += (temp1) => Console.WriteLine("b was called");
container.c += (temp1, temp2) => Console.WriteLine("c was called");
container.a();
container.b(1.5f);
container.c(1, 1.5f);
}
I would like to automate the creation of these debug lambdas using reflection, as follows:
public static void Main()
{
Container container = new Container();
GenerateDebug(container);
if(container.a != null) container.a();
if(container.b != null) container.b(1.5f);
if(container.c != null) container.c(1, 1.5f);
}
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
Action callback = () => Console.WriteLine(field.Name + " was called");
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
if(actionArgTypes.Length == 0)
{
Action action = field.GetValue(c) as System.Action;
action += callback;
field.SetValue(c, action);
}
else
{
// 1. Create an Action<T1, T2, ...> object that takes the types in 'actionArgTypes' which wraps the 'callback' action
// 2. Add this new lambda to the current Action<T1, T2, ...> field
}
}
}
I'm able to get the desired result for Actions with no arguments - the above code does indeed print out "a was called" - but I don't know how to do it for generics.
I believe I know what I need to do, just not how:
Use reflection to create an Action<T1, T2, ...> object using the types in actionArgTypes, which wraps a call to the callback action.
Add this newly created object to the Generic Action specified by the field.
How would I go about doing this, or similar that achieves the desired effect of adding such a debug callback?
Here is a rather simple implementation using Expressions, one could resort to use a ILGenerator directly, but that is not worth the hussle in this case.
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
var fieldName = field.Name;
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
// Create paramter expression for each argument
var parameters = actionArgTypes.Select(Expression.Parameter).ToArray();
// Create method call expression with a constant argument
var writeLineCall = Expression.Call(typeof(Console).GetMethod("WriteLine", new [] {typeof(string)}), Expression.Constant(fieldName + " was called"));
// Create and compile lambda using the fields type
var lambda = Expression.Lambda(field.FieldType, writeLineCall, parameters);
var #delegate = lambda.Compile();
var action = field.GetValue(c) as Delegate;
// Combine and set delegates
action = Delegate.Combine(action, #delegate);
field.SetValue(c, action);
}
}
Here is the same function using ILGenerator, that should work with .net framework 2.0+ aswell as .net core. In a real life application there should be checks, caching and probably a whole assemblybuilder:
public static void GenerateDebug(Container c)
{
Type t = c.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach(FieldInfo field in fields)
{
var fieldName = field.Name;
Type[] actionArgTypes = field.FieldType.GetGenericArguments();
var dm = new DynamicMethod(fieldName, typeof(void), actionArgTypes);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, fieldName + " was called using ilgen");
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new [] {typeof(string)}));
il.Emit(OpCodes.Ret);
var #delegate = dm.CreateDelegate(field.FieldType);
var action = field.GetValue(c) as Delegate;
// Combine and set delegates
action = Delegate.Combine(action, #delegate);
field.SetValue(c, action);
}
}

Dynamically declare a type for a method out parameter

I am struggling to describe this problem I have, but here it is:
Suppose I now have the type of a property on one member of a class (instance):
Type t = propertyInfo.PropertyType;
How do I declare or setup some variable, in order to receive a method call result later, using the out keyword?
t value; // Obviously doesn't compile, How do I declare this?
// or this?
//var value = default(t); // doesn't work
someObject.GetData(out value);
The premise here is that I don't own someObject and I am stuck with this method call signature.
If there is for example a class:
internal class Test
{
public void GetData(out int value)
{
value = 42;
}
}
The method can be called with Invoke() passing object[] as arguments:
var obj = new Test();
var type = obj.GetType();
var m = type.GetMethod("GetData");
var pars = new object[] { null };
m.Invoke(obj, pars);
I may be misunderstanding something about the complexity of the problem here, but, if you have a compile time instance of someObject, you can wrap the evil up like this:
class OutWrap<T,U> where T : U
{
private readonly SomeObject<T> obj;
public OutWrap(SomeObject<T> obj)
{
this.obj = obj;
}
public T Value
{
get
{
T t;
obj.GetData(out t);
return t;
}
}
}
and use it:
var evil = new SomeObject<int>(); // or however/whereever you get it from
var wrap = new OutWrap<int, int>(evil);
var output = wrap.Value;

Add intellisense when writing lambda's for an Action<dynamic>

This question is related to this other question.
I have the following method:
public static T GetNewData<T>(params Action<dynamic>[] actions) where T : class, new()
{
dynamic dynamicData = new DeepObject();
foreach (var action in actions)
{
action(dynamicData);
}
return Converter.Convert<T>(dynamicData);
}
The users of this method will include less technical people, even non-developers and as such the easier writing calls to this method is the better. My sticking point right now is that by using Action<dynamic> as the parameter type there is no intellisense provided to the user. In the context I know that the intellisense should be acting as if the dynamic was in fact T.
So is their a way I could either: Tell Visual Studio to use type T for the intellisense or change the parameter to be Action<T> and somehow programmatically change it to be Action<dynamic> or Action<DeepObject> so that the call to it will succeed?
EDIT: To clarify, the types that I am using for T are not of type DeepObject and they do not inherit any standard interface, the use of DeepObject is to allow setting up nested types without the user needing to explicitly instantiate at each level. This was the original usage before adding the dynamic and DeepObject code:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1 = ExampleDataFactory.GetNewData<Property1Type>(),
x => x.Property1.Property2 = ExampleDataFactory.GetNewData<Property2Type>(),
x => x.Property1.Property2.Property3 = ExampleDataFactory.GetNewData<Property3Type>(),
x => x.Property1.Property2.Property3.Property4 = true);
Here is what it looks like now:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1.Property2.Property3.Property4 = true);
EDIT: Here is the fully implemented solution based on nmclean's answer
public static DataBuilder<T> GetNewData<T>() where T : class, new()
{
return new DataBuilder<T>();
}
The DataBuilder Class:
public class DataBuilder<T>
{
public readonly T data;
public DataBuilder()
{
data = Activator.CreateInstance<T>();
}
public DataBuilder(T data)
{
this.data = data;
}
public DataBuilder<T> SetValue<T2>(Expression<Func<T, T2>> expression, T2 value)
{
var mExpr = GetMemberExpression(expression);
var obj = Recurse(mExpr);
var p = (PropertyInfo)mExpr.Member;
p.SetValue(obj, value);
return this;
}
public T Build()
{
return data;
}
public object Recurse(MemberExpression expr)
{
if (expr.Expression.Type != typeof(T))
{
var pExpr = GetMemberExpression(expr.Expression);
var parent = Recurse(pExpr);
var pInfo = (PropertyInfo) pExpr.Member;
var obj = pInfo.GetValue(parent);
if (obj == null)
{
obj = Activator.CreateInstance(pInfo.PropertyType);
pInfo.SetValue(parent, obj);
}
return obj;
}
return data;
}
private static MemberExpression GetMemberExpression(Expression expr)
{
var member = expr as MemberExpression;
var unary = expr as UnaryExpression;
return member ?? (unary != null ? unary.Operand as MemberExpression : null);
}
private static MemberExpression GetMemberExpression<T2>(Expression<Func<T, T2>> expr)
{
return GetMemberExpression(expr.Body);
}
}
The Usage:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>()
.SetValue(x=> x.Property1.EnumProperty, EnumType.Own)
.SetValue(x=> x.Property2.Property3.Property4.BoolProperty, true)
.Build();
Do not use Action<dynamic>, use Action<T>with method's constraint where T:DeepObject. Users will get intellisence and ability to use strongly typed objects:
public static DeepObject GetNewData<T>(params Action<T>[] actions)
where T : DeepObject, //restrict user only inheritors of DeepObject
new() //and require constructor
{
var data = new T();
foreach (var action in actions)
{
action(data);
}
return data;
}
Does the user need to access unknown properties or add new ones? If not, using dynamic objects seems like a step backwards. If your desired syntax does compile as an Action<T>, I think you should just declare it that way and then go with your first instinct of using the LINQ Expression API to decide how to interpret the code.
Unfortunately, although statements, such as an assignment, are part of the API, C# doesn't support converting them to expression trees. This is not allowed:
public static T GetNewData<T>(params Expression<Action<T>>[] actions)
where T : class, new() {
...
}
...
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1.Property2.Property3.Property4 = true);
Only single-line expressions that would have a return a value are supported. So I think the best you could do is something like this:
public class Assignment<T> {
public readonly Expression Expression;
public readonly object Value;
public Assignment(Expression<Func<T, object>> expression, object value) {
Expression = expression;
Value = value;
}
}
...
public static T GetNewData<T>(params Assignment<T>[] assignments)
where T : class, new() {
var data = Activator.CreateInstance<T>();
foreach (var assignment in assignments) {
// todo:
// - pull property names from assignment.Expression
// - initialize nested properties / assign to assignment.Value
}
return data;
}
...
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
new Assignment<ServicesAndFeaturesInfo>(
x => x.Property1.Property2.Property3.Property4, true));
Getting the property names from an expression tree of chained property access is not too complicated. Here is one implementation.
Of course, the new Assignment<ServicesAndFeaturesInfo>(...) is ugly and repetitive, so maybe it could be restructured to something like this:
var newData = ExampleDataFactory.NewData<ServicesAndFeaturesInfo>();
newData.Add(x => x.Property1.Property2.Property3.Property4, true);
newData.Add(...);
...
newData.Get();

Using TypeBuilder to create a pass-through constructor for the base class

Say I have a SpaceShip class, like so:
public class SpaceShip {
public SpaceShip() { }
public SpaceShip(IRocketFuelSource fuelSource) { }
}
I want to use TypeBuilder to create a type at run-time which inherits from SpaceShip, and defines one constructor for each of the ones in SpaceShip. I don't need the constructors to actually do anything except pass their arguments up to the parent ("pass-through" constructors). For example, the generated type would look something like this if expressed in C#:
public class SpaceShipSubClass : SpaceShip {
public SpaceShipSubClass() : base() { }
public SpaceShipSubClass(IRocketFuelSource fuelSource) : base(fuelSource) { }
}
To complicate things a bit, I don't actually know which class the generated type will be inheriting from until run-time (so I'll have to take into account any number of constructors, possibly with default parameters).
Is this possible? I think I could figure it out if I had a general direction to start with, it's just that I'm completely new to TypeBuilder.
Thanks!
Alright, I couldn't find anything online, so I ended up implementing my own. This should help start off anyone writing some sort of proxy, too.
public static class TypeBuilderHelper
{
/// <summary>Creates one constructor for each public constructor in the base class. Each constructor simply
/// forwards its arguments to the base constructor, and matches the base constructor's signature.
/// Supports optional values, and custom attributes on constructors and parameters.
/// Does not support n-ary (variadic) constructors</summary>
public static void CreatePassThroughConstructors(this TypeBuilder builder, Type baseType)
{
foreach (var constructor in baseType.GetConstructors()) {
var parameters = constructor.GetParameters();
if (parameters.Length > 0 && parameters.Last().IsDefined(typeof(ParamArrayAttribute), false)) {
//throw new InvalidOperationException("Variadic constructors are not supported");
continue;
}
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
var requiredCustomModifiers = parameters.Select(p => p.GetRequiredCustomModifiers()).ToArray();
var optionalCustomModifiers = parameters.Select(p => p.GetOptionalCustomModifiers()).ToArray();
var ctor = builder.DefineConstructor(MethodAttributes.Public, constructor.CallingConvention, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
for (var i = 0; i < parameters.Length; ++i) {
var parameter = parameters[i];
var parameterBuilder = ctor.DefineParameter(i + 1, parameter.Attributes, parameter.Name);
if (((int)parameter.Attributes & (int)ParameterAttributes.HasDefault) != 0) {
parameterBuilder.SetConstant(parameter.RawDefaultValue);
}
foreach (var attribute in BuildCustomAttributes(parameter.GetCustomAttributesData())) {
parameterBuilder.SetCustomAttribute(attribute);
}
}
foreach (var attribute in BuildCustomAttributes(constructor.GetCustomAttributesData())) {
ctor.SetCustomAttribute(attribute);
}
var emitter = ctor.GetILGenerator();
emitter.Emit(OpCodes.Nop);
// Load `this` and call base constructor with arguments
emitter.Emit(OpCodes.Ldarg_0);
for (var i = 1; i <= parameters.Length; ++i) {
emitter.Emit(OpCodes.Ldarg, i);
}
emitter.Emit(OpCodes.Call, constructor);
emitter.Emit(OpCodes.Ret);
}
}
private static CustomAttributeBuilder[] BuildCustomAttributes(IEnumerable<CustomAttributeData> customAttributes)
{
return customAttributes.Select(attribute => {
var attributeArgs = attribute.ConstructorArguments.Select(a => a.Value).ToArray();
var namedPropertyInfos = attribute.NamedArguments.Select(a => a.MemberInfo).OfType<PropertyInfo>().ToArray();
var namedPropertyValues = attribute.NamedArguments.Where(a => a.MemberInfo is PropertyInfo).Select(a => a.TypedValue.Value).ToArray();
var namedFieldInfos = attribute.NamedArguments.Select(a => a.MemberInfo).OfType<FieldInfo>().ToArray();
var namedFieldValues = attribute.NamedArguments.Where(a => a.MemberInfo is FieldInfo).Select(a => a.TypedValue.Value).ToArray();
return new CustomAttributeBuilder(attribute.Constructor, attributeArgs, namedPropertyInfos, namedPropertyValues, namedFieldInfos, namedFieldValues);
}).ToArray();
}
}
Usage (assuming you have a TypeBuilder object -- see here for an example):
var typeBuilder = ...; // TypeBuilder for a SpaceShipSubClass
typeBuilder.CreatePassThroughConstructors(typeof(SpaceShip));
var subType = typeBuilder.CreateType(); // Woo-hoo, proxy constructors!

Categories