Dynamically creating properties in C# for use with XmlSerializer - c#

I have an API that accepts xml messages. Suppose I have obtained object Thing from this API which looks like this:
<Thing shape="circle" color="red"/>
and is mapped to:
[XmlRoot("Thing")]
public class Thing {
[XmlAttribute("shape")]
public string Shape { get; set; }
[XmlAttribute("color")]
public string Color { get; set; }
}
Now I want to update this object so that eg. color is green. The API requires me to send it in the following format:
<Thing color="green" o_color="red"/>
Is there a way to generate o_* properties on the fly? So that when they are set outside of constructor their old value is stored in some generated property that XmlSerializer maps to o_? I know I could simply create those properties manually, but for bigger objects its a tedious work. I've tried to do that with Castle's Dynamic Proxy, which I already use in the project, but it seems it just can't add properties like that (or I haven't found out how to do that)

You have a couple of issues that need to be solved here. The fist is you must maintain state in each of your serialized objects that will tell you if a property has been altered, and what its original value is. Then your second problem is you need to build a new object dynamically based on this maintained state. With the implementation I provide you will need to determine if it meets your performance needs as it is doing a lot of Reflection. You will also have to weight its complexity with other solutions. The advantage I see with this solution is not having to maintain two very similar object.
!! Important !! This code is not Production ready. I have left a few todos in the code that need to be flushed out.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
public abstract class PropertyStateTracker
{
private class PropertyDetails
{
public object CurrentValue { get; set; }
public bool HasChanged { get; set; }
public object OriginalValue { get; set; }
}
private readonly Dictionary<string, PropertyDetails> propertyState =
new Dictionary<string, PropertyDetails>();
protected TProperty Get<TProperty>(Expression<Func<TProperty>> propertySelector)
{
string name = GetNameFromExpression(propertySelector);
PropertyDetails data;
if (!propertyState.TryGetValue(name, out data))
{
Set(propertySelector, default(TProperty));
return default(TProperty);
}
return (TProperty)data.CurrentValue;
}
protected void Set<TProperty>(Expression<Func<TProperty>> propertySelector, TProperty value)
{
string name = GetNameFromExpression(propertySelector);
PropertyDetails data;
if (!propertyState.TryGetValue(name, out data))
{
data = new PropertyDetails() { OriginalValue = value, CurrentValue = value, HasChanged = false };
propertyState[name] = data;
}
else
{
data.CurrentValue = value;
data.HasChanged = true;
}
}
[XmlIgnore]
public IEnumerable<string> ChangedProperties
{
get
{
foreach (var property in propertyState)
{
if (property.Value.HasChanged)
{
yield return property.Key;
}
}
}
}
public bool HasChanged<TProperty>(Expression<Func<TProperty>> propertySelector)
{
string name = GetNameFromExpression(propertySelector);
return HasChanged(name);
}
public bool HasChanged(string propertyName)
{
EnsurePropertyExists(propertyName);
PropertyDetails data;
if (!propertyState.TryGetValue(propertyName, out data))
{
return false;
}
return data.HasChanged;
}
public TProperty GetOriginalValue<TProperty>(Expression<Func<TProperty>> propertySelector)
{
string name = GetNameFromExpression(propertySelector);
return (TProperty)GetOriginalValue(name);
}
public object GetOriginalValue(string propertyName)
{
EnsurePropertyExists(propertyName);
PropertyDetails data;
if (!propertyState.TryGetValue(propertyName, out data))
{
return GetDefaultValue(GetPropertyInfo(propertyName).PropertyType);
}
return data.OriginalValue;
}
public TProperty GetCurrentValue<TProperty>(Expression<Func<TProperty>> propertySelector)
{
string name = GetNameFromExpression(propertySelector);
return (TProperty)GetCurrentValue(name);
}
public object GetCurrentValue(string propertyName)
{
EnsurePropertyExists(propertyName);
PropertyDetails data;
if (!propertyState.TryGetValue(propertyName, out data))
{
return GetDefaultValue(GetPropertyInfo(propertyName).PropertyType);
}
return data.CurrentValue;
}
public void Reset()
{
foreach (var property in propertyState)
{
property.Value.OriginalValue = property.Value.CurrentValue;
property.Value.HasChanged = false;
}
}
private void EnsurePropertyExists(string propertyName)
{
PropertyInfo property = GetPropertyInfo(propertyName);
if (property == null)
{
throw new ArgumentException(string.Format("A property named '{0}' was not found for type '{1}'",
propertyName, this.GetType().Name));
}
}
private PropertyInfo GetPropertyInfo(string propertyName)
{
Type type = this.GetType();
var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
return property;
}
private static object GetDefaultValue(Type t)
{
if (t.IsValueType)
return Activator.CreateInstance(t);
return null;
}
private static string GetNameFromExpression<TMember>(Expression<Func<TMember>> lambda)
{
// check to make sure a non-null lambda was provided.
if (lambda == null)
{
throw new ArgumentNullException("lambda");
}
Expression expression = lambda.Body;
// is the expression's body a unary expression.
var unaryExpression = expression as UnaryExpression;
if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)
{
expression = unaryExpression.Operand;
}
// is the expression's body a parameter expression.
var parameterExpression = expression as ParameterExpression;
if (parameterExpression != null)
{
return parameterExpression.Name;
}
// is the expression's body a member expression.
var memberExpression = expression as MemberExpression;
if (memberExpression != null)
{
return memberExpression.Member.Name;
}
// is the expression's body a method call expression.
var methodCallExpression = expression as MethodCallExpression;
if (methodCallExpression != null)
{
return methodCallExpression.Method.Name;
}
// unable to derive name. throw an exception.
throw new Exception(
string.Format("Failed to derive name from expression '{0}'",
expression));
}
}
[XmlRoot("Thing")]
public class Thing : PropertyStateTracker
{
[XmlAttribute("shape")]
public string Shape
{
get { return Get(() => Shape); }
set { Set(() => Shape, value); }
}
[XmlAttribute("color")]
public string Color
{
get { return Get(() => Color); }
set { Set(() => Color, value); }
}
}
class Program
{
private static long count = 0;
static void Main(string[] args)
{
Thing thingInstance;
System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(Thing));
string rawData = "<Thing shape=\"circle\" color=\"red\"/>";
using (System.IO.StringReader reader = new System.IO.StringReader(rawData))
{
thingInstance = (Thing)serializer.Deserialize(reader);
}
thingInstance.Color = "green";
// these two variables should be reused every time a new proxy is created. you dont want too many dynamic assemblies.
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynamicThingAssembly"), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicThingModule");
// TODO: need to figure out a way to reuse the proxyTypes being generated or you will have a
// memory leak. the type is unique based on the properties that have been modified, so you should be able to use
// the state stored inside of thingInstance to figure this out. I leave this up to you to implement.
Type proxyType = CreateProxy(moduleBuilder, thingInstance);
var proxy = Activator.CreateInstance(proxyType);
foreach (var propertyName in thingInstance.ChangedProperties)
{
proxyType.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
.SetValue(proxy, thingInstance.GetCurrentValue(propertyName));
proxyType.GetProperty("O_" + propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
.SetValue(proxy, thingInstance.GetOriginalValue(propertyName));
}
// Important this XmlSerializer should be cached, otherwise you will have a memory leak in your program.
System.Xml.Serialization.XmlSerializer serializer2 = new XmlSerializer(proxyType, new XmlRootAttribute("Thing"));
StringBuilder sb = new StringBuilder();
using (System.IO.StringWriter writer = new System.IO.StringWriter(sb))
{
serializer2.Serialize(writer, proxy);
}
Console.Write(sb.ToString());
}
private static Type CreateProxy(ModuleBuilder moduleBuilder, Thing thing)
{
var typeName = "DynamicType" + System.Threading.Interlocked.Increment(ref count).ToString("X5");
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
Type t = typeof(Thing);
foreach (var propertyName in thing.ChangedProperties)
{
var propertyInfo = t.GetProperty(propertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
CreateProperty(typeBuilder, propertyInfo.Name, propertyInfo.PropertyType);
CreateProperty(typeBuilder, "O_" + propertyInfo.Name, propertyInfo.PropertyType);
}
return typeBuilder.CreateType();
}
private static void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
var fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
// The last argument of DefineProperty is null, because the
// property has no parameters. (If you don't specify null, you must
// specify an array of Type objects. For a parameterless property,
// use an array with no elements: new Type[] {})
var propertyBuilder = typeBuilder.DefineProperty(
propertyName, PropertyAttributes.HasDefault, propertyType, null);
var attributeConstructor = typeof(XmlAttributeAttribute).GetConstructor(new Type[] { typeof(string) });
propertyBuilder.SetCustomAttribute(
new CustomAttributeBuilder(
attributeConstructor,
new object[] { propertyName.ToLower() }));
// The property set and property get methods require a special
// set of attributes.
MethodAttributes getSetAttr =
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder getPropertyMethodBuilder =
typeBuilder.DefineMethod("get_" + propertyName,
getSetAttr,
propertyType,
Type.EmptyTypes);
// Create the get methods body.
ILGenerator getPropertyMethodILGenerator = getPropertyMethodBuilder.GetILGenerator();
getPropertyMethodILGenerator.Emit(OpCodes.Ldarg_0);
getPropertyMethodILGenerator.Emit(OpCodes.Ldfld, fieldBuilder);
getPropertyMethodILGenerator.Emit(OpCodes.Ret);
// Define the "set" accessor method for CustomerName.
MethodBuilder setPropertyMethodBuilder =
typeBuilder.DefineMethod("set_" + propertyName,
getSetAttr,
null,
new Type[] { propertyType });
// Create the set methods body.
ILGenerator setPropertyMethodILGenerator = setPropertyMethodBuilder.GetILGenerator();
setPropertyMethodILGenerator.Emit(OpCodes.Ldarg_0);
setPropertyMethodILGenerator.Emit(OpCodes.Ldarg_1);
setPropertyMethodILGenerator.Emit(OpCodes.Stfld, fieldBuilder);
setPropertyMethodILGenerator.Emit(OpCodes.Ret);
// Last, we must map the two methods created above to our PropertyBuilder to
// their corresponding behaviors, "get" and "set" respectively.
propertyBuilder.SetGetMethod(getPropertyMethodBuilder);
propertyBuilder.SetSetMethod(setPropertyMethodBuilder);
}
}
}

How do you like this approach?
Thing thing;
var xs = new XmlSerializer(typeof(Thing));
thing = (Thing)xs.Deserialize(inputStream);
// Stored the old value in the property that will not be used.
thing.Shape = thing.Color;
thing.Color = "green"; // set new value
// Rename unused Shape property to o_color
var attributes = new XmlAttributes { XmlAttribute = new XmlAttributeAttribute("o_color") };
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Thing), "Shape", attributes);
xs = new XmlSerializer(typeof(Thing), overrides);
xs.Serialize(outputStream, thing);
The Color property is used for its intended purpose: to store the new color value.
While the Shape property that is not returned in your example back, we use for the previous color value are pre-renamed it.
Of course, this is only work in this exceptional case: the data types match.

Related

Project elements of List as properties of anonymous object [duplicate]

In C# 3.0 you can create anonymous class with the following syntax
var o1 = new { Id = 1, Name = "Foo" };
Is there a way to dynamic create these anonymous class to a variable?
Example:
var o1 = new { Id = 1, Name = "Foo" };
var o2 = new { SQ = 2, Birth = DateTime.Now };
Dynamic create Example:
var o1 = DynamicNewAnonymous(new NameValuePair("Id", 1), new NameValuePair("Name", "Foo"));
var o2 = DynamicNewAnonymous(new NameValuePair("SQ", 2), new NameValuePair("Birth",
DateTime.Now));
Beacuse I need to do:
dynamic o1 = new ExpandObject();
o1."ID" = 1; <--"ID" is dynamic name
o1."Name" = "Foo"; <--"Name" is dynamic name
And Scene1:
void ShowPropertiesValue(object o)
{
Type oType = o.GetType();
foreach(var pi in oType.GetProperties())
{
Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
}
}
if I call:
dynamic o1 = new ExpandObject();
o1.Name = "123";
ShowPropertiesValue(o1);
It can't show the result:
Name = 123
And also I how to Convert the ExpandoObject to AnonymouseType ?
Type type = o1.GetType();
type.GetProperties(); <--I hope it can get all property of o1
Last, I modify ShowPropertiesValue() method
void ShowPropertiesValue(object o)
{
if( o is static object ) <--How to check it is dynamic or static object?
{
Type oType = o.GetType();
foreach(var pi in oType.GetProperties())
{
Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
}
}
else if( o is dynamic object ) <--How to check it is dynamic or static object?
{
foreach(var pi in ??? ) <--How to get common dynamic object's properties info ?
{
Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
}
}
}
How to implement DynamicNewAnonymous method or how to modify the ShowPropertiesValue()?
My motivations is:
dynamic o1 = new MyDynamic();
o1.Name = "abc";
Type o1Type = o1.GetType();
var props = o1Type.GetProperties(); <--I hope can get the Name Property
If i can hook dynamicObject's GetType Method, and Compel convert to strongly-typed Type.
The above Seamless code can work fine.
Anonymous types are just regular types that are implicitly declared. They have little to do with dynamic.
Now, if you were to use an ExpandoObject and reference it through a dynamic variable, you could add or remove fields on the fly.
edit
Sure you can: just cast it to IDictionary<string, object>. Then you can use the indexer.
You use the same casting technique to iterate over the fields:
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
foreach (var property in (IDictionary<string, object>)employee)
{
Console.WriteLine(property.Key + ": " + property.Value);
}
// This code example produces the following output:
// Name: John Smith
// Age: 33
The above code and more can be found by clicking on that link.
You can create an ExpandoObject like this:
IDictionary<string,object> expando = new ExpandoObject();
expando["Name"] = value;
And after casting it to dynamic, those values will look like properties:
dynamic d = expando;
Console.WriteLine(d.Name);
However, they are not actual properties and cannot be accessed using Reflection. So the following statement will return a null:
d.GetType().GetProperty("Name")
Of cause it's possible to create dynamic classes using very cool ExpandoObject class.
But recently I worked on project and faced that Expando Object is serealized in not the same format on xml as an simple Anonymous class, it was pity =( , that is why I decided to create my own class and share it with you. It's using reflection and dynamic directive , builds Assembly, Class and Instance truly dynamicly. You can add, remove and change properties that is included in your class on fly
Here it is :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using static YourNamespace.DynamicTypeBuilderTest;
namespace YourNamespace
{
/// This class builds Dynamic Anonymous Classes
public class DynamicTypeBuilderTest
{
///
/// Create instance based on any Source class as example based on PersonalData
///
public static object CreateAnonymousDynamicInstance(PersonalData personalData, Type dynamicType, List<ClassDescriptorKeyValue> classDescriptionList)
{
var obj = Activator.CreateInstance(dynamicType);
var propInfos = dynamicType.GetProperties();
classDescriptionList.ForEach(x => SetValueToProperty(obj, propInfos, personalData, x));
return obj;
}
private static void SetValueToProperty(object obj, PropertyInfo[] propInfos, PersonalData aisMessage, ClassDescriptorKeyValue description)
{
propInfos.SingleOrDefault(x => x.Name == description.Name)?.SetValue(obj, description.ValueGetter(aisMessage), null);
}
public static dynamic CreateAnonymousDynamicType(string entityName, List<ClassDescriptorKeyValue> classDescriptionList)
{
AssemblyName asmName = new AssemblyName();
asmName.Name = $"{entityName}Assembly";
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule($"{asmName.Name}Module");
TypeBuilder typeBuilder = moduleBuilder.DefineType($"{entityName}Dynamic", TypeAttributes.Public);
classDescriptionList.ForEach(x => CreateDynamicProperty(typeBuilder, x));
return typeBuilder.CreateTypeInfo().AsType();
}
private static void CreateDynamicProperty(TypeBuilder typeBuilder, ClassDescriptorKeyValue description)
{
CreateDynamicProperty(typeBuilder, description.Name, description.Type);
}
///
///Creation Dynamic property (from MSDN) with some Magic
///
public static void CreateDynamicProperty(TypeBuilder typeBuilder, string name, Type propType)
{
FieldBuilder fieldBuider = typeBuilder.DefineField($"{name.ToLower()}Field",
propType,
FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name,
PropertyAttributes.HasDefault,
propType,
null);
MethodAttributes getSetAttr =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
MethodBuilder methodGetBuilder =
typeBuilder.DefineMethod($"get_{name}",
getSetAttr,
propType,
Type.EmptyTypes);
ILGenerator methodGetIL = methodGetBuilder.GetILGenerator();
methodGetIL.Emit(OpCodes.Ldarg_0);
methodGetIL.Emit(OpCodes.Ldfld, fieldBuider);
methodGetIL.Emit(OpCodes.Ret);
MethodBuilder methodSetBuilder =
typeBuilder.DefineMethod($"set_{name}",
getSetAttr,
null,
new Type[] { propType });
ILGenerator methodSetIL = methodSetBuilder.GetILGenerator();
methodSetIL.Emit(OpCodes.Ldarg_0);
methodSetIL.Emit(OpCodes.Ldarg_1);
methodSetIL.Emit(OpCodes.Stfld, fieldBuider);
methodSetIL.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(methodGetBuilder);
propertyBuilder.SetSetMethod(methodSetBuilder);
}
public class ClassDescriptorKeyValue
{
public ClassDescriptorKeyValue(string name, Type type, Func<PersonalData, object> valueGetter)
{
Name = name;
ValueGetter = valueGetter;
Type = type;
}
public string Name;
public Type Type;
public Func<PersonalData, object> ValueGetter;
}
///
///Your Custom class description based on any source class for example
/// PersonalData
public static IEnumerable<ClassDescriptorKeyValue> GetAnonymousClassDescription(bool includeAddress, bool includeFacebook)
{
yield return new ClassDescriptorKeyValue("Id", typeof(string), x => x.Id);
yield return new ClassDescriptorKeyValue("Name", typeof(string), x => x.FirstName);
yield return new ClassDescriptorKeyValue("Surname", typeof(string), x => x.LastName);
yield return new ClassDescriptorKeyValue("Country", typeof(string), x => x.Country);
yield return new ClassDescriptorKeyValue("Age", typeof(int?), x => x.Age);
yield return new ClassDescriptorKeyValue("IsChild", typeof(bool), x => x.Age < 21);
if (includeAddress)
yield return new ClassDescriptorKeyValue("Address", typeof(string), x => x?.Contacts["Address"]);
if (includeFacebook)
yield return new ClassDescriptorKeyValue("Facebook", typeof(string), x => x?.Contacts["Facebook"]);
}
///
///Source Data Class for example
/// of cause you can use any other class
public class PersonalData
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country { get; set; }
public int Age { get; set; }
public Dictionary<string, string> Contacts { get; set; }
}
}
}
It is also very simple to use DynamicTypeBuilder, you just need put few lines like this:
public class ExampleOfUse
{
private readonly bool includeAddress;
private readonly bool includeFacebook;
private readonly dynamic dynamicType;
private readonly List<ClassDescriptorKeyValue> classDiscriptionList;
public ExampleOfUse(bool includeAddress = false, bool includeFacebook = false)
{
this.includeAddress = includeAddress;
this.includeFacebook = includeFacebook;
this.classDiscriptionList = DynamicTypeBuilderTest.GetAnonymousClassDescription(includeAddress, includeFacebook).ToList();
this.dynamicType = DynamicTypeBuilderTest.CreateAnonymousDynamicType("VeryPrivateData", this.classDiscriptionList);
}
public object Map(PersonalData privateInfo)
{
object dynamicObject = DynamicTypeBuilderTest.CreateAnonymousDynamicInstance(privateInfo, this.dynamicType, classDiscriptionList);
return dynamicObject;
}
}
I hope that this code snippet help somebody =) Enjoy!

Reflection.Emit InvalidProgramException

I´m currently trying to create a "Mock" for an interface using Reflection.Emit.
Therefore I created a base class that I use for all dynamically generated mocks.
For properties in the interface I want to call a "Get" Method in the base class that returns the property value.
public class Mock
{
public static TIf Wrap<TIf>() where TIf : class
{
if (!typeof(TIf).IsInterface)
throw new Exception(typeof(TIf) + " is no interface");
var asmBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);
var modBuilder = asmBuilder.DefineDynamicModule("Mock", true);
var typename = "ImplOf" + typeof(TIf).Name.Replace(" ", "") + ".Mock";
var typeBuilder = modBuilder.DefineType(typename, TypeAttributes.Public, typeof(WrapperBase));
typeBuilder.AddInterfaceImplementation(typeof(TIf));
// methods
foreach (var meth in typeof(TIf).GetMethods())
{
var del = typeof(WrapperBase).GetMethod(meth.ReturnType != typeof(void) ? "TryCallMethod" : "TryCallMethodOneWay");
var mb = typeBuilder.DefineMethod(meth.Name, meth.Attributes ^ MethodAttributes.Abstract);
mb.SetParameters(meth.GetParameters().Select(p => p.ParameterType)?.ToArray());
mb.SetReturnType(meth.ReturnType);
var mbil = mb.GetILGenerator();
mbil.Emit(OpCodes.Ldarg_0);
mbil.Emit(OpCodes.Ldstr, meth.Name);
for (var i = 0; i < meth.GetParameters().Length; i++)
{
mbil.Emit(OpCodes.Ldarg, i + 1);
}
mbil.Emit(OpCodes.Call, del);
mbil.Emit(OpCodes.Ret);
}
// properties
foreach (var prop in typeof(TIf).GetProperties())
{
var propertyBuilder = typeBuilder.DefineProperty(prop.Name, prop.Attributes, prop.PropertyType, null);
if (prop.CanRead)
{
var getterDelegate = typeof(WrapperBase).GetMethod("TryGetProperty");
var getter = typeBuilder.DefineMethod("get_" + prop.Name, MethodAttributes.Public, prop.PropertyType, Type.EmptyTypes);
var gil = getter.GetILGenerator();
gil.Emit(OpCodes.Ldarg_0);
gil.Emit(OpCodes.Ldstr, prop.Name);
gil.Emit(OpCodes.Callvirt, getterDelegate);
gil.Emit(OpCodes.Castclass, prop.PropertyType);
gil.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getter);
}
if (prop.CanWrite)
{
var setterDelegate = typeof(WrapperBase).GetMethod("TrySetProperty");
var setter = typeBuilder.DefineMethod("set_" + prop.Name, MethodAttributes.Public, typeof(void), Type.EmptyTypes);
var sil = setter.GetILGenerator();
sil.Emit(OpCodes.Ldarg_0);
sil.Emit(OpCodes.Ldstr, prop.Name);
sil.Emit(OpCodes.Ldarg_1);
sil.Emit(OpCodes.Call, setterDelegate);
sil.Emit(OpCodes.Ret);
propertyBuilder.SetSetMethod(setter);
}
}
var retType = typeBuilder.CreateType();
return retType.GetConstructor(new Type[0]).Invoke(new object[0]) as TIf;
}
public abstract class WrapperBase
{
public event Func<string, object[], object> OnTryCallMethod;
public event Action<string, object[]> OnTryCallMethodOneWay;
public event Func<string, object> OnTryGetProperty;
public event Action<string, object> OnTrySetProperty;
/// <inheritdoc />
public object TryCallMethod(string name, object[] pars)
{
return OnTryCallMethod?.Invoke(name, pars);
}
/// <inheritdoc />
public void TryCallMethodOneWay(string name, object[] pars)
{
OnTryCallMethodOneWay?.Invoke(name, pars);
}
/// <inheritdoc />
public object TryGetProperty(string name)
{
return OnTryGetProperty?.Invoke(name);
}
/// <inheritdoc />
public void TrySetProperty(string name, object value)
{
OnTrySetProperty?.Invoke(name, value);
}
}
}
Unfortunately I always get an InvalidProgramException when trying to read a "mocked" property.
Setting the property (which will delegate the call also to some base class method) works fine, same for method calls.
For testing, I created a quite simple interface:
public interface ITest
{
void Show(string text);
string Text { get; set; }
}
Now I´m calling the mock like this:
var wrapped = Mock.Wrap<ITest>();
// ***************** works - EventHandler is called with correct parameters!
((Mock.WrapperBase)wrapped).OnTryCallMethodOneWay += (s, objects) => { };
wrapped.Show("sss");
// ***************** works - EventHandler is called with correct parameters!
wrapped.Text = "";
((Mock.WrapperBase)wrapped).OnTrySetProperty += (s, val) => { };
// ***************** does NOT work - getting InvalidProgramException
((Mock.WrapperBase)wrapped).OnTryGetProperty += s => "";
var t = wrapped.Text;
After a bit of debugging, I've found your issue. I noticed that
wrapped.Text = "" was stepping into TryCallMethodOneWay when it's clearly written as calling TrySetProperty.
This is because foreach (var meth in typeof(TIf).GetMethods()) is going to return you getter and setter methods. That is; you're defining the getters and setters twice.
This is solved by a simple check:
var properties = typeof(TIf).GetProperties();
var propertyMethods = properties.SelectMany(p => new[] { p.GetGetMethod(), p.GetSetMethod() }).ToLookup(p => p);
foreach (var meth in typeof(TIf).GetMethods())
{
if (propertyMethods.Contains(meth))
continue;
...
}
Now, you also have to mark your implementing methods as Virtual if they're to implement an interface. So, you'll need to change the code to be the following:
var getter = typeBuilder.DefineMethod("get_" + prop.Name, MethodAttributes.Public | MethodAttributes.Virtual, prop.PropertyType, Type.EmptyTypes);
And
var setter = typeBuilder.DefineMethod("set_" + prop.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), new[] { prop.PropertyType });
And your code should work without issue

How can I create new object based on another one?

I have some not useful object with, let's say, 30 properties. Half of them are useful for me, so I want to create new useful object with only properties I need so the rest doesn't take space in object visualizers. I don't want to define new class and type them down. I want something like
var list = new List<SomeType> { usefulProp1, usefulProp2, ... };
var usefulObject = new NewItem(notUsefulObject, list);
where SomeType is not string (list doesn't contain property names).
if its something permanent then doing it properly would be to create a class that inherits from your base class and populate only the properties that you need.
public UsefulObject : NotUsefulObject
{
public int MyProperty
{
get
{
return base.MyProperty; // this is arbitrary you can do it however you want.
}
set
{
MyProperty = value;
}
}
}
Then you can use your reuse your useful object however you want.
var list = new List<UsefulObject>();
var list = new List<Expression<Func<object>>> { () => notUsefulObject.usefulProp1, () => notUsefulObject.usefulProp2... };
var nm = new AssemblyName("MyDynamicAssembly");
TypeBuilder tb = Thread.GetDomain().DefineDynamicAssembly(nm, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(nm.Name, nm.Name + ".dll").DefineType("NewItem", TypeAttributes.Public);
const MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
foreach (Expression b in list.Select(x => x.Body))
{
MemberInfo mi = ((MemberExpression)b).Member;
Type t = b.Type;
FieldBuilder fb = tb.DefineField(mi.Name.ToLower(), t, FieldAttributes.Private);
PropertyBuilder pb = tb.DefineProperty(mi.Name, PropertyAttributes.HasDefault, t, null);
MethodBuilder getBld = tb.DefineMethod("get_" + mi.Name, GetSetAttr, t, Type.EmptyTypes);
ILGenerator getGen = getBld.GetILGenerator();
getGen.Emit(OpCodes.Ldarg_0);
getGen.Emit(OpCodes.Ldfld, fb);
getGen.Emit(OpCodes.Ret);
MethodBuilder setBld = tb.DefineMethod("set_" + mi.Name, GetSetAttr, null, new[] { t });
ILGenerator setGen = setBld.GetILGenerator();
setGen.Emit(OpCodes.Ldarg_0);
setGen.Emit(OpCodes.Ldarg_1);
setGen.Emit(OpCodes.Stfld, fb);
setGen.Emit(OpCodes.Ret);
pb.SetGetMethod(getBld);
pb.SetSetMethod(setBld);
}
object usefulObject = Activator.CreateInstance(tb.CreateType());
Because you said this problem was specific to object visualizers, the best solution is to make a Debugger Type Proxy for the class which can be used as a proxy.
[DebuggerTypeProxy(typeof(SomeTypeDebugView))]
public class SomeType
{
public string Foo { get; set; }
public string Bar { get; set; }
internal class SomeTypeDebugView
{
private SomeType _someType;
public SomeTypeDebugView(SomeType someType)
{
_someType = someType;
}
public string Foo { get { return _someType.Foo; } }
}
}
class Program
{
static void Main()
{
var someType = new SomeType();
someType.Foo = "foo";
someType.Bar = "bar";
Debugger.Break();
}
}
This will cause Bar to be hidden in the debug visualizer by default unless you choose to view the "Raw Type"
If you are looking for a more one time debugging type you can use annonamous types to create the new type you need in the watch window, for example his is new {Foo = someType.Foo, Bar = someType.Bar }
This also could be used with LINQ to perform the select over a IEnumerable, here for example is someTypeList.Select(x=> new {Foo = x.Foo, Bar = x.Bar})

Conditional method calls in an expression tree

I'm trying to add an additional method call to my expression tree, but I'm slightly confused how to implement it. Here is what I'm currently working with:
private static Action<object, object> CreateSetter(SetterInfo info)
{
var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
return (s, v) => { };
var objParameter = Expression.Parameter(typeof(object));
var valueParameter = Expression.Parameter(typeof(object));
//This is the method call I'm trying to add
if (info.Name[0] == 'G' && info.Type.Name == TaxDataConstant.ParcelFeat)
{
var convertParcelFeatCall = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));
}
var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, Expression.Constant(propertyInfo.PropertyType));
var objCast = Expression.Convert(objParameter, info.Type);
var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType);
var property = Expression.Property(objCast, propertyInfo);
var assignment = Expression.Assign(property, valueCast);
var lambda = Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);
return lambda.Compile();
}
What I want to happen is:
1) If the name of the type in my SetterInfo object is ParcelFeat and the Properties name begins with 'G' I want to call ConvertParcelFeat on valueParameter and then call ChangeType on the return.
2) If the name of the type is anything other than ParcelFeat call Changetype as normal with out the additional steps
What I'm confused is how to build the conditional. I'm assuming the way I'm doing it in the above code is wrong and I need to use something like Expression.IfThen() to to build the conditional. I'm also unsure how I can chain the method calls like I want.
You do not need in Expression.IfThen because for each specific SetterInfo you combine exactly one specific lambda instance.
Just plug in convertParcelFeatCall in proper place of your ExpressionTree and all should work just fine.
So your code might look like:
class Program
{
static void Main(string[] args)
{
var program = new Program();
var weightLambda = program.DoInternal("Weight").ToString()
== "(Param_0, Param_1) => (Convert(Param_0).Weight = Convert(ChangeType(Param_1, System.Object)))";
var goodiesLambda = program.DoInternal("Goodies").ToString()
== "(Param_0, Param_1) => (Convert(Param_0).Goodies = Convert(ChangeType(Param_1, ConvertParcelFeat(Param_1, \"Goodies\"))))";
Console.WriteLine("WeightLambda is Ok: {0}\nGoodiesLambda is Ok: {1}", weightLambda, goodiesLambda);
}
public Action<Object, Object> Do(string name)
{
return DoInternal(name).Compile();
}
public Expression<Action<object, object>> DoInternal(string name)
{
var info = new {Name = name, Type = typeof(Program)};
var propertyInfo = info.Type.GetProperty(info.Name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var objParameter = Expression.Parameter(typeof(object));
var valueParameter = Expression.Parameter(typeof(object));
//This is the method call I'm trying to add
Expression toBeTypeChanged;
if (info.Name[0] == 'G' && info.Type.Name == "Program")
{
toBeTypeChanged = Expression.Call(ConvertParcelFeatMethod, valueParameter, Expression.Constant(info.Name));
}
else
{
toBeTypeChanged = Expression.Constant(propertyInfo.PropertyType);
}
var changeTypeCall = Expression.Call(ChangeTypeMethod, valueParameter, toBeTypeChanged);
var objCast = Expression.Convert(objParameter, info.Type);
var valueCast = Expression.Convert(changeTypeCall, propertyInfo.PropertyType);
var property = Expression.Property(objCast, propertyInfo);
var assignment = Expression.Assign(property, valueCast);
return Expression.Lambda<Action<object, object>>(assignment, objParameter, valueParameter);
}
public object Weight { get; set; }
public object Goodies { get; set; }
public static object ChangeType(object valueParameter, object constant)
{
return null;
}
public static object ConvertParcelFeat(object valueParameter, object constant)
{
return null;
}
public MethodInfo ConvertParcelFeatMethod
{
get { return typeof(Program).GetMethod("ConvertParcelFeat"); }
}
public MethodInfo ChangeTypeMethod
{
get { return typeof(Program).GetMethod("ChangeType"); }
}
}

How can I generate this property implementation using Expressions instead of emitting IL?

I'm trying to generate classes at runtime that implement property getters with a body that calls a method on the generated class's base class. Here's an example of a simple interface, along with a hand-written implementation that I'm trying to duplicate and the base class.
public interface IGenerated : IBase { decimal Property1 { get; } }
public class GeneratedByHand : ImplBase<IGenerated> {
public decimal Property1 { get { return Get(s => s.Property1); } }
}
public interface IBase { string _KeyPrefix { get; set; } }
public abstract class ImplBase<T> : IBase
where T : IBase
{
public virtual string _KeyPrefix { get; set; }
protected virtual TResult Get<TResult>(Expression<Func<T, TResult>> property) {
return GetValue<TResult>(GetPropertyName(property));
}
private string GetPropertyName<TResult>(Expression<Func<T, TResult>> property) {
return ""; // reflection stuff to get name from property expression goes here
}
private TResult GetValue<TResult>(string keyPart) {
return default(TResult); // does something like: return ReallyGetValue<TResult>(_KeyPrefix + keyPart);
}
}
I have a working implementation of the generator that emits IL to build the method, but if I can do it with Expressions I think that will be easier to expand and maintain. I will need to look for custom attributes on the property definitions and use that to call different method overloads on the base class in the property implementations.
Here's where I've gotten building an expression for the property get implementation. What I don't really understand is building the Call expression, if I'm setting it up correctly to do the equivalent of this.Get() or base.Get(). Right now it throws a System.ArgumentException : Invalid argument value Parameter name: method at CompileToMethod
public void CreateExpressionForGetMethod(MethodBuilder getBuilder, Type interfaceType, Type baseType, PropertyInfo property, MethodInfo getMethod)
{
var settingsParam = Expression.Parameter(interfaceType, "s");
var propGetterExpr = Expression.Property(settingsParam, property);
var propGetterExprFuncType = typeof(Func<,>).MakeGenericType(interfaceType, property.PropertyType);
var propGetterLambda = Expression.Lambda(propGetterExprFuncType, propGetterExpr, settingsParam);
var baseGetMethodInfo =
baseType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(m => {
var parameters = m.GetParameters();
return m.Name == "Get" &&
parameters != null && parameters.Count() == 1 && parameters[0].ParameterType != typeof(string);
})
.First().MakeGenericMethod(property.PropertyType);
var getExprType = typeof(Expression<>).MakeGenericType(propGetterExprFuncType);
var getExprParam = Expression.Parameter(getExprType, "expression");
var getCallExpr = Expression.Call(Expression.Parameter(baseType, "inst"), baseGetMethodInfo, propGetterLambda);
var getFuncType = typeof(Func<,>).MakeGenericType(getExprType, property.PropertyType);
var propLambda = Expression.Lambda(getFuncType, getCallExpr, getExprParam);
propLambda.CompileToMethod(getBuilder);
}
I'm not really sure where to go from here. I've tried a few other variations of arguments to Expression.Call, but everything else had Call throwing exceptions for the parameters being the wrong types.
Here's a buildable version of all the sample code I'm working with, including the working IL emitter:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using NUnit.Framework;
namespace ExpressionGenerationTest
{
[TestFixture]
public class UnitTests
{
[Test]
public void CreateAndSaveAssembly()
{
var implGenerator = new ImplBuilder();
var generatedType = implGenerator.CreateImplementation(typeof(IGenerated));
implGenerator.SaveAssembly();
}
}
public interface IBase { string _KeyPrefix { get; set; } }
public abstract class ImplBase<T> : IBase
where T : IBase
{
public virtual string _KeyPrefix { get; set; }
protected virtual TResult Get<TResult>(Expression<Func<T, TResult>> property) { return GetValue<TResult>(GetPropertyName(property)); }
private string GetPropertyName<TResult>(Expression<Func<T, TResult>> property) { return ""; } // reflection stuff to get name from property expression goes here
private TResult GetValue<TResult>(string keyPart) { return default(TResult); } // does something like: return ReallyGetValue(_KeyPrefix + keyPart);
}
public interface IGenerated : IBase { decimal Property1 { get; } }
public class GeneratedByHand : ImplBase<IGenerated> { public decimal Property1 { get { return Get(s => s.Property1); } } }
public class ImplBuilder
{
private const string _assemblyNameBase = "ExpressionGenerationTest.Impl";
public static ImplBuilder Default { get { return _default.Value; } }
private static readonly Lazy<ImplBuilder> _default = new Lazy<ImplBuilder>(() => new ImplBuilder());
private ConcurrentDictionary<Type, Type> _types = new ConcurrentDictionary<Type, Type>();
private AssemblyBuilder _assemblyBuilder = null;
private volatile ModuleBuilder _moduleBuilder = null;
private object _lock = new object();
private void EnsureInitialized()
{
if (_moduleBuilder == null) {
lock (_lock) {
if (_moduleBuilder == null) {
_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(_assemblyNameBase), AssemblyBuilderAccess.RunAndSave);
_moduleBuilder = _assemblyBuilder.DefineDynamicModule(_assemblyBuilder.GetName().Name, _assemblyNameBase + ".dll");
}
}
}
}
public void SaveAssembly() { _assemblyBuilder.Save(_assemblyNameBase + ".dll"); }
public TSettings CreateInstance<TSettings>() { return (TSettings)Activator.CreateInstance(_types.GetOrAdd(typeof(TSettings), CreateImplementation)); }
public void CreateImplementations(IEnumerable<Type> types) { foreach (var t in types) _types.GetOrAdd(t, InternalCreateImplementation); }
public Type CreateImplementation(Type interfaceType) { return _types.GetOrAdd(interfaceType, InternalCreateImplementation); }
private Type InternalCreateImplementation(Type interfaceType)
{
EnsureInitialized();
var baseType = typeof (ImplBase<>).MakeGenericType(interfaceType);
var typeBuilder = _moduleBuilder.DefineType(
(interfaceType.IsInterface && interfaceType.Name.StartsWith("I")
? interfaceType.Name.Substring(1)
: interfaceType.Name) + "Impl",
TypeAttributes.Public | TypeAttributes.Class |
TypeAttributes.AutoClass | TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,
baseType,
new [] {interfaceType});
foreach (var p in GetPublicProperties(interfaceType).Where(pi => pi.DeclaringType != typeof(IBase))) {
var iGet = p.GetGetMethod();
if (iGet != null) {
var getBuilder =
typeBuilder.DefineMethod(iGet.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
p.PropertyType, Type.EmptyTypes);
//EmitILForGetMethod(getBuilder, interfaceType, baseType, p, iGet);
CreateExpressionForGetMethod(getBuilder, interfaceType, baseType, p, iGet);
typeBuilder.DefineMethodOverride(getBuilder, iGet);
}
}
var implementationType = typeBuilder.CreateType();
return implementationType;
}
public void CreateExpressionForGetMethod(MethodBuilder getBuilder, Type interfaceType, Type baseType, PropertyInfo property, MethodInfo getMethod)
{
var settingsParam = Expression.Parameter(interfaceType, "s");
var propGetterExpr = Expression.Property(settingsParam, property);
var propGetterExprFuncType = typeof(Func<,>).MakeGenericType(interfaceType, property.PropertyType);
var propGetterLambda = Expression.Lambda(propGetterExprFuncType, propGetterExpr, settingsParam);
var baseGetMethodInfo =
baseType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(m => {
var parameters = m.GetParameters();
return m.Name == "Get" &&
parameters != null && parameters.Count() == 1 && parameters[0].ParameterType != typeof(string);
})
.First().MakeGenericMethod(property.PropertyType);
var getExprType = typeof(Expression<>).MakeGenericType(propGetterExprFuncType);
var getExprParam = Expression.Parameter(getExprType, "expression");
var getCallExpr = Expression.Call(Expression.Parameter(baseType, "inst"), baseGetMethodInfo, propGetterLambda);
var getFuncType = typeof(Func<,>).MakeGenericType(getExprType, property.PropertyType);
var propLambda = Expression.Lambda(getFuncType, getCallExpr, getExprParam);
propLambda.CompileToMethod(getBuilder);
}
public void EmitILForGetMethod(MethodBuilder getBuilder, Type interfaceType, Type baseType, PropertyInfo property, MethodInfo getMethod)
{
var getGen = getBuilder.GetILGenerator();
var retVal = getGen.DeclareLocal(property.PropertyType);
var expParam = getGen.DeclareLocal(typeof(ParameterExpression));
var expParams = getGen.DeclareLocal(typeof(ParameterExpression[]));
getGen.Emit(OpCodes.Ldarg_0);
getGen.Emit(OpCodes.Ldtoken, interfaceType);
getGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
getGen.Emit(OpCodes.Ldstr, "s");
getGen.Emit(OpCodes.Call, typeof(Expression).GetMethod("Parameter", new [] {typeof(Type), typeof(string)}));
getGen.Emit(OpCodes.Stloc, expParam);
getGen.Emit(OpCodes.Ldloc, expParam);
getGen.Emit(OpCodes.Ldtoken, getMethod);
getGen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new [] {typeof(RuntimeMethodHandle)}, null));
getGen.Emit(OpCodes.Castclass, typeof(MethodInfo));
getGen.Emit(OpCodes.Call, typeof(Expression).GetMethod("Property", new[] {typeof(Expression), typeof(MethodInfo)}));
getGen.Emit(OpCodes.Ldc_I4_1);
getGen.Emit(OpCodes.Newarr, typeof(ParameterExpression));
getGen.Emit(OpCodes.Stloc, expParams);
getGen.Emit(OpCodes.Ldloc, expParams);
getGen.Emit(OpCodes.Ldc_I4_0);
getGen.Emit(OpCodes.Ldloc, expParam);
getGen.Emit(OpCodes.Stelem_Ref);
getGen.Emit(OpCodes.Ldloc, expParams);
var lambdaMethodInfo =
typeof(Expression).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(x => {
var parameters = x.GetParameters();
return x.Name == "Lambda" &&
x.IsGenericMethodDefinition &&
parameters.Count() == 2 &&
parameters[0].ParameterType == typeof(Expression) &&
parameters[1].ParameterType == typeof(ParameterExpression[]);
}).FirstOrDefault();
var lambdaFuncType = typeof(Func<,>);
lambdaFuncType = lambdaFuncType.MakeGenericType(interfaceType, property.PropertyType);
lambdaMethodInfo = lambdaMethodInfo.MakeGenericMethod(lambdaFuncType);
getGen.Emit(OpCodes.Call, lambdaMethodInfo);
var baseGetMethodInfo =
baseType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(m => {
var parameters = m.GetParameters();
return m.Name == "Get" &&
parameters != null && parameters.Count() == 1 && parameters[0].ParameterType != typeof(string);
}).FirstOrDefault();
baseGetMethodInfo = baseGetMethodInfo.MakeGenericMethod(property.PropertyType);
getGen.Emit(OpCodes.Callvirt, baseGetMethodInfo);
getGen.Emit(OpCodes.Stloc_0);
var endOfMethod = getGen.DefineLabel();
getGen.Emit(OpCodes.Br_S, endOfMethod);
getGen.MarkLabel(endOfMethod);
getGen.Emit(OpCodes.Ldloc_0);
getGen.Emit(OpCodes.Ret);
}
// from http://stackoverflow.com/a/2444090/224087
public static PropertyInfo[] GetPublicProperties(Type type)
{
if (!type.IsInterface)
return type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
var propertyInfos = new List<PropertyInfo>();
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0) {
var subType = queue.Dequeue();
foreach (var subInterface in subType.GetInterfaces()) {
if (considered.Contains(subInterface))
continue;
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
var typeProperties = subType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
var newPropertyInfos = typeProperties.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
}
}
What I don't really understand is building the Call expression, if I'm setting it up correctly to do the equivalent of this.Get() or base.Get().
If you are calling a virtual method, then this.Get(), which accesses the most-derived override (which could even be defined in a descendant of the current class), uses the callvirt instruction. And it doesn't matter what type you reflect against to get the MethodInfo, because they all share the same virtual table slot.
To emit base.Get(), you must
use the call instruction
reflect against the base class type
Because callvirt does some extra things besides v-table lookup, including a null pointer check, the C# compiler uses it for all virtual and non-virtual calls, except those involving the base keyword.
In particular, anonymous delegates and lambdas can't make use of the base keyword, since only descendant types can make non-virtual calls to virtual methods (at least in verifiable code), and the lambda is actually hosted by a closure type.
So unfortunately for your use case, there's no way to express a base call using lambda notation or expression trees. Expression.CompileToMethod only generates callvirt. Well, that isn't exactly correct. It generates call for calls to static methods and instance methods of value types. But instance methods of reference types use only callvirt. You can see this in System.Linq.Expressions.Compiler.LambdaCompiler.UseVirtual
Thanks #hvd for confirming this based on comments found in the Microsoft Reference Source for UseVirtual

Categories

Resources