DuplexChannelFactory < Reflection Interface > - c#

Using TypeGenerator Class
public class TypeGenerator
{
/// <summary>
/// internal cache for already generated types
/// </summary>
private static Dictionary<Type, Type> asyncTypeCache = new Dictionary<Type, Type>();
/// <summary>
/// provides a cache for the modules
/// </summary>
private static Dictionary<string, ModuleBuilder> moduleBuilderCache = new Dictionary<string, ModuleBuilder>();
/// <summary>
/// Generates the Async version of the TSync type.
/// the generate type repects the AsyncPattern and it is already decorated with attributes for WCF operations
/// </summary>
/// <typeparam name="TSync">The Sync version of type</typeparam>
/// <returns>A type that is the Async version of the TSync type, that implements the AsyncPattern for WCF</returns>
public Type GenerateAsyncInterfaceFor<TSync>() where TSync : class
{
Type syncType = typeof(TSync);
if (asyncTypeCache.ContainsKey(syncType)) return asyncTypeCache[syncType];
if (!syncType.IsInterface) throw new InvalidOperationException("Only interface type could be transformed");
var asynchAssemblyName = string.Format("{0}.Async", syncType.Namespace);
TypeBuilder typeBuilder =
GetModuleBuilder(asynchAssemblyName)
.DefineType(
string.Format("{0}.Async.{1}", syncType.Namespace, syncType.Name),
(syncType.IsPublic ? TypeAttributes.Public : 0) |
TypeAttributes.Abstract |
TypeAttributes.Interface);
foreach (var method in syncType.GetAllInterfaceMethods())
{
AddBeginAsynchVersionForMethod(typeBuilder, method, #"http://tempuri.org");
AddEndAsynchVersionForMethod(typeBuilder, method);
}
var serviceContractConstructor = typeof(ServiceContractAttribute).GetConstructor(new Type[0]);
var attribuiteBuilder =
new CustomAttributeBuilder(
serviceContractConstructor,
new object[0]);
typeBuilder.SetCustomAttribute(attribuiteBuilder);
Type asyncType = typeBuilder.CreateType();
asyncTypeCache.Add(syncType, asyncType);
return asyncType;
}
/// <summary>
/// Creates a End verison of a sync method, that implements the AsyncPattern
/// </summary>
/// <param name="typeBuilder">the tipebuilder where the type is being building</param>
/// <param name="method">information about the sync version of the method</param>
private void AddEndAsynchVersionForMethod(TypeBuilder typeBuilder, MethodInfo method)
{
string endMethodName = string.Format("End{0}", method.Name);
var parameters =
method.GetParameters()
.Select(x =>
new
{
Type = x.ParameterType,
Name = x.Name,
Attributes = x.Attributes,
})
.ToList();
parameters.Add(
new
{
Type = typeof(IAsyncResult),
Name = "asyncResult",
Attributes = ParameterAttributes.None,
});
var methodBuilder =
typeBuilder
.DefineMethod(
endMethodName,
method.Attributes,
method.CallingConvention,
method.ReturnType,
parameters.Select(x => x.Type).ToArray());
for (int i = 0; i < parameters.Count(); i++)
{
var parameter = parameters[i];
methodBuilder.DefineParameter(i + 1, parameter.Attributes, parameter.Name);
}
}
/// <summary>
/// Creates a Begin verison of a sync method, that implements the AsyncPattern
/// </summary>
/// <param name="typeBuilder">the tipebuilder where the type is being building</param>
/// <param name="method">information about the sync version of the method</param>
private void AddBeginAsynchVersionForMethod(TypeBuilder typeBuilder, MethodInfo method, string nameSpace)
{
string beginMethodName = string.Format("Begin{0}", method.Name);
var parametersTypeList = method.GetParameters().Select(x => x.ParameterType).ToList();
var parametersNameList = method.GetParameters().Select(x => x.Name).ToList();
var parametersAttributeList = method.GetParameters().Select(x => x.Attributes).ToList();
parametersTypeList.Add(typeof(AsyncCallback));
parametersAttributeList.Add(ParameterAttributes.None);
parametersNameList.Add("callBack");
parametersTypeList.Add(typeof(object));
parametersAttributeList.Add(ParameterAttributes.None);
parametersNameList.Add("statusObject");
var methodBuilder =
typeBuilder
.DefineMethod(
beginMethodName,
method.Attributes,
method.CallingConvention,
typeof(IAsyncResult),
parametersTypeList.ToArray());
for (int i = 0; i < parametersTypeList.Count(); i++)
{
methodBuilder.DefineParameter(i + 1, parametersAttributeList[i], parametersNameList[i]);
}
var operationContractConstructor = typeof(OperationContractAttribute).GetConstructor(new Type[0]);
var asynchPatternProperty = typeof(OperationContractAttribute).GetProperty("AsyncPattern");
var actionProperty = typeof(OperationContractAttribute).GetProperty("Action");
var actionValue = string.Format("{0}/{1}/{2}", nameSpace, method.DeclaringType.Name, method.Name);
var replyActionProperty = typeof(OperationContractAttribute).GetProperty("ReplyAction");
var replyActionValue = string.Format("{0}/{1}/{2}Response", nameSpace, method.DeclaringType.Name, method.Name);
var attribuiteBuilder =
new CustomAttributeBuilder(
operationContractConstructor,
new object[0],
new[] { asynchPatternProperty, actionProperty, replyActionProperty },
new object[] { true, actionValue, replyActionValue });
methodBuilder.SetCustomAttribute(attribuiteBuilder);
}
/// <summary>
/// provides a ModelBuilder with the required assembly name
/// </summary>
/// <param name="requiredAssemblyName">the assembly name for where the type will be generated in</param>
/// <returns>a model builder</returns>
/// <remarks>in this version the model builder is not cached, it could be interesting to generate all the types in the same assembly by caching the model builder</remarks>
private ModuleBuilder GetModuleBuilder(string requiredAssemblyName)
{
if (moduleBuilderCache.ContainsKey(requiredAssemblyName))
{
return moduleBuilderCache[requiredAssemblyName];
}
AssemblyName assemblyName = new AssemblyName(requiredAssemblyName);
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
moduleBuilderCache[requiredAssemblyName] = moduleBuilder;
return moduleBuilder;
}
}
and TypeExtentions Class
public static class TypeExtensions
{
/// <summary>
/// extracts all the methods fromthe given interface type and from all the inherited ones too
/// </summary>
/// <param name="type">the type fromwhich extracts all the methods</param>
/// <returns>list of MemberInfo representing the methods</returns>
public static IEnumerable<MethodInfo> GetAllInterfaceMethods(this Type type)
{
IEnumerable<MethodInfo> methods = type.GetMethods();
foreach (var subType in type.GetInterfaces())
{
methods = methods.Union(GetAllInterfaceMethods(subType));
}
return methods;
}
}
I 'm able to convert a Synchronous Interface to Asynchronous one.
How to use DuplexChannelFactory with a pre-defined reflection Asynchronous interface ?
var myInterface = new TypeGenerator ( ) . GenerateAsyncInterfaceFor<mySynchronousInterface> ( );
var Client = new DuplexChannelFactory<myInterface> ( new InstanceContext ( new myClass ( ) ) , "myConfiguration" );
I'm getting the following issue:
The type or namespace name 'myInterface' could not be found (are you
missing a using directive or an assembly reference?)
I'm trying to code a mid-tier WCF interface.

The syntax you are using is for compile time typing, of course the types you are making are generated at runtime, so it isn't going to work. It is possible though.
How to: Examine and Instantiate Generic Types with Reflection
Here's how the code will look (I'm assuming myClass was already defined with source code, if not it would just be another Activator.CreateInstance call)
Type t = typeof(DuplexChannelFactory<>);
Type typedDuplexChannelFactory = t.MakeGenericType(new Type[]{myInterface});
var Client = Activator.CreateInstance(typedDuplexChannelFactory, new object[]{new InstanceContext ( new myClass ( ) ) , "myConfiguration"});

Related

System.InvalidCastException: 'Unable to cast object of type 'ClassName' to type InterfaceName'.'

I am working on a C# application. I have a ClassLibrary type project which has an interface and some classes which implement this interface. Code is:
public interface IUserInterface
{
String GetName();
int Function(int a, int b);
}
public class UserClass : IUserInterface
{
public String GetName() { return "Add"; }
public int Function(int a, int b) { return a + b; }
}
public class UserClass1 : IUserInterface
{
public String GetName() { return "Add"; }
public int Function(int a, int b) { return a + b; }
}
public class UserClass2 : IUserInterface
{
public String GetName() { return "Add"; }
public int Function(int a, int b) { return a + b; }
}
My requirement is that i have to find all the implementations of IUserInterface, create the instances of those implementations using reflection and store all these instances in a List. My code for this is:
class Program
{
private static List<Type> nameTypeDict = new List<Type>();
private static List<IUserInterface> instances = new List<IUserInterface>();
static void Main(string[] args)
{
Program obj = new Program();
Assembly ass = Assembly.LoadFrom("ClassLibrary.dll");
foreach (Type t in ass.GetExportedTypes())
{
if (t.GetInterface("IUserInterface", true) != null)
{
Console.WriteLine("Found Type: {0}", t.Name);
nameTypeDict.Add(t);//Add to Dictonary
}
}
foreach (var type in nameTypeDict)
{
var typeObject = Activator.CreateInstance(type);
IUserInterface typeObj = (IUserInterface)typeObject;
instances.Add(typeObject);
}
Console.ReadKey();
}
}
I did manage to create the instance, but gets exception at
IUserInterface typeObj = (IUserInterface)typeObject;
The exception is:
System.InvalidCastException: 'Unable to cast object of type
'ClassLibrary.UserClass' to type 'ClassLibrary.IUserInterface'.'
How can this be resolved ? I know i am making some silly mistake but, i am unable to figure it out. The reason why i am casting it is because i have to save the instance in the IUserInterface type list.
I have created an assembly utils which can get instances of all classes with the given interface from a .dll file. Following is the code I used to obtain those results:
public static class AssemblyUtils
{
/// <summary>
/// Get Application folder path
/// </summary>
/// <returns></returns>
public static string GetExeFilePath()
{
return Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
}
/// <summary>
/// Get all types of object that implement the type <typeparamref name="T"/> inside the assembly
/// </summary>
/// <typeparam name="T">Interface type</typeparam>
/// <param name="filename">File path of the assembly</param>
/// <returns>An enumerable of type <see cref="Type"/> that implements <typeparamref name="T"/></returns>
public static IEnumerable<Type> GetTypesFromAssembly<T>(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException($"DLL file not found. File path: {filename}");
var asm = Assembly.LoadFrom(filename);
var types = asm.GetTypes();
var typeFilter = new TypeFilter(InterfaceFilter);
foreach (var type in types)
{
var interfaces = type.FindInterfaces(typeFilter, typeof(T).ToString());
if (interfaces.Length > 0)
// We found the type that implements the interface
yield return type;
}
}
/// <summary>
/// Creates an <see cref="IEnumerable{T}"/> instance that implements interface of type <typeparamref name="T"/>
/// </summary>
/// <typeparam name="T">Type of object to find and return</typeparam>
/// <param name="filename">Name of the assembly file</param>
/// <returns>Instance of <see cref="IEnumerable{T}"/></returns>
public static IEnumerable<T> GetInterfacesFromAssembly<T>(string filename, params object[] args)
{
var types = GetTypesFromAssembly<T>(filename);
foreach (var type in types)
{
yield return (T)Activator.CreateInstance(type, args);
}
}
/// <summary>
/// Creates an <see cref="IEnumerable{T}"/> instance that implements interface of type <typeparamref name="T"/>
/// </summary>
/// <typeparam name="T">Type of object to find and return</typeparam>
/// <param name="directory">Path of directory containing assemblies</param>
/// <returns>Instance of <see cref="IEnumerable{T}"/></returns>
public static IEnumerable<T> GetInterfacesFromAssemblyDirectory<T>(string directory, params object[] args)
{
if (!Directory.Exists(directory))
{
throw new DirectoryNotFoundException($"Directory could not be found. Path: { directory }");
}
return Directory.GetFiles(directory, "*.dll").SelectMany(filename => GetInterfacesFromAssembly<T>(filename, args));
}
/// <summary>
/// Type filter for filtering the interface in a class
/// </summary>
/// <param name="typeObj">Object type</param>
/// <param name="criteriaObj">Filter criteria</param>
/// <returns>Whether the criteria is meet or not</returns>
private static bool InterfaceFilter(Type typeObj, object criteriaObj)
{
return typeObj.ToString() == criteriaObj.ToString();
}
}
Change the line which is throwing exception to this
IUserInterface typeObj = (IUserInterface)Activator.CreateInstance(typeObject);
You need to understand the loading contexts. In your case you must load the same assembly into the default context for it to understand that it's not just a matter of naming collision.
For a full guide on context, check here: https://learn.microsoft.com/en-us/dotnet/framework/deployment/best-practices-for-assembly-loading
The default load context contains assemblies found by probing the global assembly cache, the host assembly store if the runtime is hosted (for example, in SQL Server), and the ApplicationBase and PrivateBinPath of the application domain. Most overloads of the Load method load assemblies into this context.
To solve your issue, use the load method as described here: https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load?view=netframework-4.8#System_Reflection_Assembly_Load_System_String_

c# creating a dynamically anonymous types (var) [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I need to create a anonymous type (HAS to be a var). Like this:
var sizes = new {
size = new { Medium = "1", Large = "-3", XL = "10%" }
};
It has to be dynamically so the next time this could also happen:
var sizes = new {
size = new { 3XL = "5", 4XL = "5%", 5XL = "-10%" }
};
How do I do this in C# winforms?
How do i fill in the var sizes? It has to be in this order!
You can create a dynamic type at runtime which contains methods and properties of any type using System.Reflection.Emit, you can assign default values into your properties within the dynamic type created. This is not a trivial exercise and it needs some work, but when you have the base code complete using it in your code is easy.
First you need to attach your dynamic type to your current AppDomain.
private AssemblyName _assemblyName;
private AssemblyBuilder _asssemblyBuilder;
private ModuleBuilder _moduleBuilder;
private Dictionary<SignatureBuilder, Type> _classes;
private ReaderWriterLock _rwLock;
private TypeBuilder _typeBuilder;
private string _typeName;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="moduleName">The name of the assembly module.</param>
public DynamicTypeBuilder(string moduleName)
{
// Make sure the page reference exists.
if (moduleName == null) throw new ArgumentNullException("moduleName");
// Create the nw assembly
_assemblyName = new AssemblyName(moduleName);
_asssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.Run);
// Create only one module, therefor the
// modile name is the assembly name.
_moduleBuilder = _asssemblyBuilder.DefineDynamicModule(_assemblyName.Name);
// Get the class unique signature.
_classes = new Dictionary<SignatureBuilder, Type>();
_rwLock = new ReaderWriterLock();
}
The dynamic property class can be
/// <summary>
/// Dynamic property builder, with value assigned.
/// </summary>
public class DynamicPropertyValue
{
object value;
string name;
Type type;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="name">The name of the property.</param>
/// <param name="type">The type of the property</param>
/// <param name="value">The value of the property.</param>
public DynamicPropertyValue(string name, Type type, object value)
{
if (name == null) throw new ArgumentNullException("name");
if (type == null) throw new ArgumentNullException("type");
if (value == null) throw new ArgumentNullException("value");
this.name = name;
this.type = type;
this.value = value;
}
/// <summary>
/// Gets, the property name.
/// </summary>
public string Name
{
get { return name; }
}
/// <summary>
/// Gets, the property type.
/// </summary>
public Type Type
{
get { return type; }
}
/// <summary>
/// Gets, the property value.
/// </summary>
public object Value
{
get { return value; }
}
}
The dynamic method class can be
/// <summary>
/// Dynamic method builder.
/// </summary>
public class DynamicMethod
{
string name;
IEnumerable<Type> parameters;
Type returnType;
Action<TypeBuilder> buildAction = null;
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="name">The name of the method.</param>
/// <param name="parameters">The collection parameter types.</param>
/// <param name="returnType">The return type.</param>
public DynamicMethod(string name, IEnumerable<Type> parameters, Type returnType)
{
if (name == null) throw new ArgumentNullException("name");
this.name = name;
this.parameters = parameters;
this.returnType = returnType;
}
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="name">The name of the method.</param>
/// <param name="parameters">The collection parameter types.</param>
/// <param name="returnType">The return type.</param>
/// <param name="buildAction">The build action.</param>
public DynamicMethod(string name, IEnumerable<Type> parameters, Type returnType, Action<TypeBuilder> buildAction)
{
if (name == null) throw new ArgumentNullException("name");
this.name = name;
this.parameters = parameters;
this.returnType = returnType;
this.buildAction = buildAction;
}
/// <summary>
/// Gets, the method name.
/// </summary>
public string Name
{
get { return name; }
}
/// <summary>
/// Gets, the collection of parameters
/// </summary>
public IEnumerable<Type> Parameters
{
get { return parameters; }
}
/// <summary>
/// Gets, the return type.
/// </summary>
public Type ReturnType
{
get { return returnType; }
}
/// <summary>
/// Gets, build action.
/// </summary>
public Action<TypeBuilder> BuildAction
{
get { return buildAction; }
}
}
Start the create process.
/// <summary>
/// Create a new instance of the dynamic type.
/// </summary>
/// <param name="typeName">The name of the type.</param>
/// <param name="properties">The collection of properties to create in the type.</param>
/// <param name="methods">The collection of methods to create in the type.</param>
/// <returns>The new instance of the type.</returns>
public object Create(string typeName, IEnumerable<DynamicPropertyValue> properties, IEnumerable<DynamicMethod> methods)
{
// Make sure the page reference exists.
if (typeName == null) throw new ArgumentNullException("typeName");
if (properties == null) throw new ArgumentNullException("properties");
if (methods == null) throw new ArgumentNullException("methods");
_typeName = typeName;
// Create the dynamic type collection
List<DynamicProperty> prop = new List<DynamicProperty>();
foreach (DynamicPropertyValue item in properties)
prop.Add(new DynamicProperty(item.Name, item.Type));
// Return the create type.
object instance = CreateEx(typeName, prop.ToArray(), methods);
PropertyInfo[] infos = instance.GetType().GetProperties();
// Assign each type value
foreach (PropertyInfo info in infos)
info.SetValue(instance, properties.First(u => u.Name == info.Name).Value, null);
// Return the instance with values assigned.
return instance;
}
If this is something you can use the complete source code for the dynamic type builder can be found at https://github.com/nequeo/misc/blob/master/csharp/DynamicTypeBuilder.cs

Expression tree to initialize new anonymous object with arbitrary number of properties

I'm trying to use LINQ expression trees to initialize a new anonymous object with a subset of fields from a passed-in object. The subset of fields will typically be a single property but could be more (4 or so).
An example:
void DoWork(Type t)
{
//do some work to figure out which properties I want to use
List<PropertyInfo>() props = (from p in t.GetProperties()
where p.HasAttribute(MyAttribute)
select p).ToList();
//now I want to create a lambda expression that's like:
// (x=> new {x.Prop1, x.Prop2, ...})
//for each property in the list props
//create parameter
var param = Expression.Parameter(t,"t");
//get list of expressions for properties
var initValues = (from p in props
select Expression.PropertyOrField(param, p.Name)
).ToList();
//build expression body
Expression body = Expression. //<<<< I have no idea what to do here
//create lambda
dynamic propLambda = Expression.Lambda(body, param);
//use it! MyFunction( x=> new {x.Prop1, x.Prop2,...});
MyFunction(lambda);
}
The bad news: Since you're gonna build the anonymous type dynamically at runtime, it doesn't exist at compile time, as it would if the compiler encountered a new {...} in your code. There's no way around Reflection.Emit, which isn't tivial.
The good news: I've already done it, because I had the same needs. Used ILDASM to see what the compiler generates and mimic that as closely as possible.
So without further ado:
/// <summary>
/// Creates types that are much like anonymous types.
/// </summary>
public static class TupleFactory
{
// the dynamic module used to emit new types
private static readonly ModuleBuilder _module = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName { Name = nameof(TupleFactory) }, AssemblyBuilderAccess.Run).DefineDynamicModule(nameof(TupleFactory), false);
// the generic type definitions constructed so far
private static readonly Dictionary<ICollection<string>, Type> _genericTypeDefinitions = new Dictionary<ICollection<string>, Type>(CollectionComparer<string>.Default);
// the new expression factory singletons constructed so far
private static readonly Dictionary<ICollection<KeyValuePair<string, Type>>, ITupleFactory> _newExpressionFactories = new Dictionary<ICollection<KeyValuePair<string, Type>>, ITupleFactory>(new CollectionComparer<KeyValuePair<string, Type>>(KeyValueComparer<string, Type>.Default));
// some reflection objects used
private static readonly ConstructorInfo _objectCtor = typeof(object).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo _objectEquals = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(object) }, null);
private static readonly MethodInfo _objectGetHashCode = typeof(object).GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
private static readonly MethodInfo _objectToString = typeof(object).GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
private static readonly MethodInfo _stringFormat = typeof(string).GetMethod("Format", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string), typeof(object[]) }, null);
private static readonly MethodInfo _equalityComparerDefaultGetter;
private static readonly MethodInfo _equalityComparerEquals;
private static readonly MethodInfo _equalityComparerGetHashCode;
static TupleFactory()
{
// init more reflection objects
_equalityComparerDefaultGetter = typeof(EqualityComparer<>).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetGetMethod();
var eqT = typeof(EqualityComparer<>).GetGenericArguments()[0];
_equalityComparerEquals = typeof(EqualityComparer<>).GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance, null, new[] { eqT, eqT }, null);
_equalityComparerGetHashCode = typeof(EqualityComparer<>).GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance, null, new[] { eqT }, null);
}
/// <summary>
/// Gets a <see cref="ITupleFactory"/> singleton for a sequence of properties.
/// </summary>
/// <param name="properties">Name/Type pairs for the properties.</param>
public static ITupleFactory Create(IEnumerable<KeyValuePair<string, Type>> properties)
{
// check input
if (properties == null) throw new ArgumentNullException(nameof(properties));
var propList = properties.ToList();
if (propList.Select(p => p.Key).Distinct().Count() != propList.Count)
throw new ArgumentException("Property names must be distinct.");
lock (_module) // locks access to the static dictionaries
{
ITupleFactory result;
if (_newExpressionFactories.TryGetValue(propList, out result)) // we already have it
return result;
var propertyNames = propList.Select(p => p.Key).ToList();
Type genericTypeDefinition;
if (!_genericTypeDefinitions.TryGetValue(propertyNames, out genericTypeDefinition))
{
#region create new generic type definition
{
var typeBuilder = _module.DefineType($"<>f__AnonymousType{_newExpressionFactories.Count}`{propertyNames.Count}", TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
var genParams = propertyNames.Count > 0
? typeBuilder.DefineGenericParameters(propertyNames.Select(p => $"<{p}>j__TPar").ToArray())
: new GenericTypeParameterBuilder[0];
// attributes on type
var debuggerDisplay = "\\{ " + string.Join(", ", propertyNames.Select(n => $"{n} = {{{n}}}")) + " }";
// ReSharper disable AssignNullToNotNullAttribute
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(DebuggerDisplayAttribute).GetConstructor(new[] { typeof(string) }), new object[] { debuggerDisplay }));
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
// ReSharper restore AssignNullToNotNullAttribute
var fields = new List<FieldBuilder>();
var props = new List<PropertyBuilder>();
foreach (var name in propertyNames)
{
var genParam = genParams[fields.Count];
var field = typeBuilder.DefineField($"<{name}>i__Field", genParam, FieldAttributes.Private | FieldAttributes.InitOnly);
fields.Add(field);
var property = typeBuilder.DefineProperty(name, PropertyAttributes.None, genParam, null);
props.Add(property);
var getter = typeBuilder.DefineMethod($"get_{name}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, genParam, Type.EmptyTypes);
var il = getter.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Ret);
property.SetGetMethod(getter);
}
#region ctor
{
// ReSharper disable once CoVariantArrayConversion
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, genParams);
var il = ctorBuilder.GetILGenerator();
// call base class ctor
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, _objectCtor);
// assign args to fields
for (var i = 0; i < fields.Count; i++)
{
il.Emit(OpCodes.Ldarg_0);
EmitLdarg(il, i + 1);
il.Emit(OpCodes.Stfld, fields[i]);
}
il.Emit(OpCodes.Ret);
}
#endregion
#region override Equals
{
var equals = typeBuilder.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(bool), new[] { typeof(object) });
typeBuilder.DefineMethodOverride(equals, _objectEquals);
var il = equals.GetILGenerator();
il.DeclareLocal(typeBuilder);
var retFalse = il.DefineLabel();
var ret = il.DefineLabel();
// local = argument as (the type being constructed)?
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Isinst, typeBuilder);
il.Emit(OpCodes.Stloc_0);
// push result of the "as" operator
il.Emit(OpCodes.Ldloc_0);
foreach (var field in fields)
{
var comparer = typeof(EqualityComparer<>).MakeGenericType(field.FieldType);
var defaultGetter = TypeBuilder.GetMethod(comparer, _equalityComparerDefaultGetter);
var equalsMethod = TypeBuilder.GetMethod(comparer, _equalityComparerEquals);
// check if the result of the previous check is false
il.Emit(OpCodes.Brfalse, retFalse);
// push EqualityComparer<FieldType>.Default.Equals(this.field, other.field)
il.Emit(OpCodes.Call, defaultGetter);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Callvirt, equalsMethod);
}
// jump to the end with what was the last result
il.Emit(OpCodes.Br_S, ret);
// push false
il.MarkLabel(retFalse);
il.Emit(OpCodes.Ldc_I4_0);
il.MarkLabel(ret);
il.Emit(OpCodes.Ret);
}
#endregion
#region override GetHashCode
{
var getHashCode = typeBuilder.DefineMethod("GetHashCode", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(int), Type.EmptyTypes);
typeBuilder.DefineMethodOverride(getHashCode, _objectGetHashCode);
var il = getHashCode.GetILGenerator();
// init result with seed
il.Emit(OpCodes.Ldc_I4, HashCode.Seed);
foreach (var field in fields)
{
var comparer = typeof(EqualityComparer<>).MakeGenericType(field.FieldType);
var defaultGetter = TypeBuilder.GetMethod(comparer, _equalityComparerDefaultGetter);
var getHashCodeMethod = TypeBuilder.GetMethod(comparer, _equalityComparerGetHashCode);
// hash so far * factor
il.Emit(OpCodes.Ldc_I4, HashCode.Factor);
il.Emit(OpCodes.Mul);
// ... + EqualityComparer<FieldType>.GetHashCode(field)
il.Emit(OpCodes.Call, defaultGetter);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Callvirt, getHashCodeMethod);
il.Emit(OpCodes.Add);
}
il.Emit(OpCodes.Ret);
}
#endregion
#region override ToString
{
var toString = typeBuilder.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(string), Type.EmptyTypes);
typeBuilder.DefineMethodOverride(toString, _objectToString);
var template = "{{ " + string.Join(", ", propertyNames.Select((n, i) => $"{n} = {{{i}}}")) + " }}";
var il = toString.GetILGenerator();
// push template
il.Emit(OpCodes.Ldstr, template);
// push new array
EmitLdc(il, fields.Count);
il.Emit(OpCodes.Newarr, typeof(object));
var index = 0;
foreach (var field in fields)
{
il.Emit(OpCodes.Dup); // duplicate array ref
EmitLdc(il, index); // push array index
// store boxed field in array
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, field);
il.Emit(OpCodes.Box, field.FieldType);
il.Emit(OpCodes.Stelem, typeof(object));
index++;
}
il.Emit(OpCodes.Call, _stringFormat);
il.Emit(OpCodes.Ret);
}
#endregion
genericTypeDefinition = typeBuilder.CreateType();
}
#endregion
_genericTypeDefinitions.Add(propertyNames, genericTypeDefinition);
}
var type = propList.Count == 0 ? genericTypeDefinition : genericTypeDefinition.MakeGenericType(propList.Select(p => p.Value).ToArray());
result = new TupleFactoryImpl(type, propertyNames);
_newExpressionFactories.Add(propList, result);
return result;
}
}
/// <summary>
/// Gets a <see cref="NewExpression"/> for a tuple type with the specified properties.
/// </summary>
public static NewExpression MakeNewExpression(IEnumerable<KeyValuePair<string, Expression>> properties)
{
var props = properties.ToList();
var tupleFactory = Create(props.Select(p => new KeyValuePair<string, Type>(p.Key, p.Value.Type)));
return tupleFactory.MakeNewExpression(props.Select(p => p.Value));
}
private sealed class TupleFactoryImpl : ITupleFactory
{
public Type TupleType { get; }
private readonly ConstructorInfo _ctor;
private readonly MemberInfo[] _properties;
public TupleFactoryImpl(Type tupleType, IEnumerable<string> propertyNames)
{
TupleType = tupleType;
_ctor = tupleType.GetConstructors().Single();
var propsByName = tupleType.GetProperties().ToDictionary(p => p.Name);
_properties = propertyNames.Select(name => (MemberInfo)propsByName[name]).ToArray();
}
public NewExpression MakeNewExpression(IEnumerable<Expression> arguments)
{
return Expression.New(_ctor, arguments, _properties);
}
}
/// <summary>
/// Helper function to pick the optimal op code.
/// </summary>
private static void EmitLdarg(ILGenerator il, int index)
{
if (index < 0) throw new ArgumentOutOfRangeException();
switch (index)
{
case 0: il.Emit(OpCodes.Ldarg_0); break;
case 1: il.Emit(OpCodes.Ldarg_1); break;
case 2: il.Emit(OpCodes.Ldarg_2); break;
case 3: il.Emit(OpCodes.Ldarg_3); break;
default:
if (index <= byte.MaxValue)
il.Emit(OpCodes.Ldarg_S, (byte)index);
else if (index <= short.MaxValue)
il.Emit(OpCodes.Ldarg, (short)index);
else
throw new ArgumentOutOfRangeException();
break;
}
}
/// <summary>
/// Helper function to pick the optimal op code.
/// </summary>
private static void EmitLdc(ILGenerator il, int i)
{
switch (i)
{
case -1: il.Emit(OpCodes.Ldc_I4_M1); break;
case 0: il.Emit(OpCodes.Ldc_I4_0); break;
case 1: il.Emit(OpCodes.Ldc_I4_1); break;
case 2: il.Emit(OpCodes.Ldc_I4_2); break;
case 3: il.Emit(OpCodes.Ldc_I4_3); break;
case 4: il.Emit(OpCodes.Ldc_I4_4); break;
case 5: il.Emit(OpCodes.Ldc_I4_5); break;
case 6: il.Emit(OpCodes.Ldc_I4_6); break;
case 7: il.Emit(OpCodes.Ldc_I4_7); break;
case 8: il.Emit(OpCodes.Ldc_I4_8); break;
default:
if (i >= byte.MinValue && i <= byte.MaxValue)
il.Emit(OpCodes.Ldc_I4_S, (byte)i);
else
il.Emit(OpCodes.Ldc_I4, i);
break;
}
}
}
/// <summary>
/// Compute a hash code.
/// </summary>
public struct HashCode
{
// magic numbers for hash code
public const int Seed = 0x20e699b;
public const int Factor = unchecked((int)0xa5555529);
private readonly int? _value;
private HashCode(int value)
{
_value = value;
}
/// <summary>
/// Convert to the actual hash code based on what was added so far.
/// </summary>
public static implicit operator int(HashCode hc) => hc._value ?? 0;
/// <summary>
/// Add a hash code to the state.
/// </summary>
/// <returns>An updated <see cref="HashCode"/>.</returns>
public static HashCode operator +(HashCode hc, int other) => new HashCode(unchecked((hc._value == null ? Seed : hc._value.Value * Factor) + other));
/// <summary>
/// Add a sequence of hash code to the state.
/// </summary>
/// <returns>An updated <see cref="HashCode"/>.</returns>
public static HashCode operator +(HashCode hc, IEnumerable<int> others) => others.Aggregate(hc, (a, c) => a + c);
}
/// <summary>
/// <see cref="IEqualityComparer{T}"/> for <see cref="KeyValuePair{TKey, TValue}"/>.
/// </summary>
public sealed class KeyValueComparer<TKey, TValue> : IEqualityComparer<KeyValuePair<TKey, TValue>>
{
/// <summary>
/// Gets the singleton.
/// </summary>
public static KeyValueComparer<TKey, TValue> Default { get; } = new KeyValueComparer<TKey, TValue>();
private readonly IEqualityComparer<TKey> _keyComparer;
private readonly IEqualityComparer<TValue> _valueComparer;
/// <summary>
/// Initialize by specifying <see cref="IEqualityComparer{T}"/>s for key and value.
/// </summary>
public KeyValueComparer(IEqualityComparer<TKey> keyComparer = null, IEqualityComparer<TValue> valueComparer = null)
{
_keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
_valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
}
/// <summary>
/// Equality.
/// </summary>
public bool Equals(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y) => _keyComparer.Equals(x.Key, y.Key) && _valueComparer.Equals(x.Value, y.Value);
/// <summary>
/// Hash code.
/// </summary>
public int GetHashCode(KeyValuePair<TKey, TValue> obj) => new HashCode() + _keyComparer.GetHashCode(obj.Key) + _valueComparer.GetHashCode(obj.Value);
}
/// <summary>
/// <see cref="IEqualityComparer{T}"/> for a collection.
/// </summary>
public sealed class CollectionComparer<TElement> : IEqualityComparer<ICollection<TElement>>
{
/// <summary>
/// Gets an instance using <see cref="EqualityComparer{T}.Default"/> as the element comparer.
/// </summary>
public static CollectionComparer<TElement> Default { get; } = new CollectionComparer<TElement>();
private readonly IEqualityComparer<TElement> _elementComparer;
/// <summary>
/// Initialize with a specific element comparer.
/// </summary>
public CollectionComparer(IEqualityComparer<TElement> elementComparer = null)
{
_elementComparer = elementComparer ?? EqualityComparer<TElement>.Default;
}
/// <summary>
/// Determines whether the specified objects are equal.
/// </summary>
/// <returns>
/// true if the specified objects are equal; otherwise, false.
/// </returns>
public bool Equals(ICollection<TElement> x, ICollection<TElement> y)
{
if (x == null) return y == null;
if (y == null) return false;
return x.Count == y.Count && x.SequenceEqual(y, _elementComparer);
}
/// <summary>
/// Returns a hash code for the specified object.
/// </summary>
/// <returns>
/// A hash code for the specified object.
/// </returns>
/// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
public int GetHashCode(ICollection<TElement> obj)
{
var result = new HashCode() + typeof(TElement).GetHashCode();
if (obj == null) return result;
result += obj.Count;
result += obj.Select(element => _elementComparer.GetHashCode(element));
return result;
}
}
Usage:
void DoWork(Type type)
{
var props = type.GetProperties().Where(p => p.HasAttribute(MyAttribute)).ToList();
var tupleFactory = TupleFactory.Create(props.Select(p => new KeyValuePair<string, Type>(p.Name, p.PropertyType)));
var param = Expression.Parameter(type, "x");
var newEx = tupleFactory.MakeNewExpression(props.Select(p => Expression.Property(param, p)));
var lambda = Expression.Lambda(newEx, param); // <-- type is LambdaExpression, not dynamic
MyFunction(lambda);
}

Getting Enum from a Dynamically created Enum

Can you help me with this, in C#
Given an Enum
public enum InterferenceEnum
{
None = 0,
StrongNoiseSource = 1,
MediumNoiseSource = 2,
VerySensitiveSignal = 4,
SensitiveSignal = 8,
}
and a Dynamic Enum from this
public Type GenerateEnumerations(List<string> lEnumItems, string assemblyName)
{
// Create Base Assembly Objects
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName asmName = new AssemblyName(assemblyName);
AssemblyBuilder asmBuilder = appDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
// Create Module and Enumeration Builder Objects
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(assemblyName + "_module");
EnumBuilder enumBuilder = modBuilder.DefineEnum(assemblyName, TypeAttributes.Public, typeof(int));
enumBuilder.DefineLiteral("None", 0);
int flagCnt = 1;
foreach (string fmtObj in lEnumItems)
{
enumBuilder.DefineLiteral(fmtObj, flagCnt);
flagCnt++;
}
var retEnumType = enumBuilder.CreateType();
//asmBuilder.Save(asmName.Name + ".dll");
return retEnumType;
}
using the function above
List<string> nets_List = new List<string>() { "A", "B", "C" };
netListEnum = GenerateEnumerations(nets_List, "netsenum");
Now if i have a variable with value "None", i can get the enum by
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
using the first Enum, i can get the enum of string "None"
InterferenceEnum enum = (InterferenceEnum)Enum.Parse(typeof(InterferenceEnum), "None");
How can i get the enum for the dynamic generated enum?
var enum = (netListEnum.GetType())Enum.Parse(typeof(netListEnum.GetType()), "None");
the above code is wrong because i still "casting" it with the netListEnum Type, here is the updated code
var enum = Enum.Parse(netListEnum, "None");
You already have it -- "Enum.Parse()" returns you an enum of the specified type, boxed into an object. But the boxed object is of the enum type you created; if you call "GetType()" on it it returns that same type:
List<string> nets_List = new List<string>() { "A", "B", "C" };
var netListEnumType = GenerateEnumerations(nets_List, "netsenum");
var typeName = netListEnumType.Name; // returns "netsenum"
var typeTypeName = netListEnumType.GetType().Name; // returns "RuntimeType", the actual name of the instantiated Type class.
foreach (var enumName in nets_List)
{
var enumValBoxed = Enum.Parse(netListEnumType, enumName);
Console.WriteLine(enumValBoxed.ToString()); // Writes "A", "B" and "C"
Debug.Assert(enumValBoxed.GetType() == netListEnumType); // no assert yay.
}
The only problem I see with your code is that you are doing netListEnum.GetType() but netListEnum is already of type Type -- the type you created, in fact -- so that is not necessary.
If you need to pass the enum thereby created on to some generic method in a generic object, e.g. a Dictionary<string, TEnum>, you can call it via reflection with MakeGenericMethod
my Enum maker:
public class XEnum
{
private EnumBuilder enumBuilder;
private int index;
private AssemblyBuilder _ab;
private AssemblyName _name;
public XEnum(string enumname)
{
AppDomain currentDomain = AppDomain.CurrentDomain;
_name = new AssemblyName("MyAssembly");
_ab = currentDomain.DefineDynamicAssembly(
_name, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = _ab.DefineDynamicModule("MyModule");
enumBuilder = mb.DefineEnum(enumname, TypeAttributes.Public, typeof(int));
}
/// <summary>
/// adding one string to enum
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public FieldBuilder add(string s)
{
FieldBuilder f = enumBuilder.DefineLiteral(s, index);
index++;
return f;
}
/// <summary>
/// adding array to enum
/// </summary>
/// <param name="s"></param>
public void addRange(string[] s)
{
for (int i = 0; i < s.Length; i++)
{
enumBuilder.DefineLiteral(s[i], i);
}
}
/// <summary>
/// getting index 0
/// </summary>
/// <returns></returns>
public object getEnum()
{
Type finished = enumBuilder.CreateType();
_ab.Save(_name.Name + ".dll");
Object o1 = Enum.Parse(finished, "0");
return o1;
}
public Type getType()
{
Type finished = enumBuilder.CreateType();
_ab.Save(_name.Name + ".dll");
return finished;
}
/// <summary>
/// getting with index
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public object getEnum(int i)
{
Type finished = enumBuilder.CreateType();
_ab.Save(_name.Name + ".dll");
Object o1 = Enum.Parse(finished, i.ToString());
return o1;
}
}
to make Enum From String Array:
public static object STE(string[] #enum)
{
if (#enum.Length > 0)
{
XEnum xe = new XEnum("Enum");
xe.addRange(#enum);
return xe.getEnum();
}
else return null;
}
to get a selected string from enum :
public static object STE(string sel, string[] #enum)
{
XEnum xe = new XEnum("Enum");
xe.addRange(#enum);
var obj= xe.getType();
return Enum.Parse(obj, sel);
}
to use STE's put them into static class,
so to use this :
string[] ab = {"a", "b"};
object abEnum = STE(ab); //creates Enum
private object aEnum = STE("a", ab); //gets selected Value

How to map two expressions of differing types?

I'll start with some classes...
The Domain Entity:
public class Account
{
public int Id { get; set; }
public double Balance { get; set; }
public string CustomerName { get; set; }
}
The View Model:
public class AccountModel
{
public int Id { get; set; }
public double Bal { get; set; }
public string Name { get; set; }
}
The Repository:
My repository has a method on it that takes an expression and returns a list, like this:
public interface IAccountRepository
{
IEnumerable<Account> Query(Expression<Func<Account, bool>> expression);
}
The Problem
My application generates an Expression<Func<AccountModel, bool>> in the UI. I need to somehow convert or map the EXPRESSION from AccountModel to Account so that I can use it in my Query method. I say "map" because, if you notice, my model and domain objects are similar, but don't necessarily have the same property names.
How can this be done?
This sounds like a job for AutoMapper. Automapper allows you to map one class to another at one point in time and use this mapping configuration later on.
See the Projection page on the wiki for the kind of thing you are after.
Update As you are using Entity Framework, here is an update for remapping your expression from using AccountModel to Account.
In the CompositionRoot of your application, set up AutoMapper like so (ignore Code Contract statements if you do not use Code Contracts):
var accountModelMap = Mapper.CreateMap<AccountModel, Account>();
Contract.Assume(accountModelMap != null);
accountModelMap.ForMember(account => account.Id, expression => expression.MapFrom(model => model.Id));
accountModelMap.ForMember(account => account.Balance, expression => expression.MapFrom(model => model.Bal));
accountModelMap.ForMember(account => account.CustomerName, expression => expression.MapFrom(model => model.Name));
This configures how the two data types relate to eachother.
Implement an ExpressionVisitor to use AutoMapper to rebind member access from one type to another.
/// <summary>
/// An <see cref="ExpressionVisitor"/> implementation which uses <see href="http://automapper.org">AutoMapper</see> to remap property access from elements of type <typeparamref name="TSource"/> to elements of type <typeparamref name="TDestination"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source element.</typeparam>
/// <typeparam name="TDestination">The type of the destination element.</typeparam>
public class AutoMapVisitor<TSource, TDestination> : ExpressionVisitor
{
private readonly ParameterExpression _newParameter;
private readonly TypeMap _typeMap = Mapper.FindTypeMapFor<TSource, TDestination>();
/// <summary>
/// Initialises a new instance of the <see cref="AutoMapVisitor{TSource, TDestination}"/> class.
/// </summary>
/// <param name="newParameter">The new <see cref="ParameterExpression"/> to access.</param>
public AutoMapVisitor(ParameterExpression newParameter)
{
Contract.Requires(newParameter != null);
_newParameter = newParameter;
Contract.Assume(_typeMap != null);
}
[ContractInvariantMethod]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
private void ObjectInvariant()
{
Contract.Invariant(_typeMap != null);
Contract.Invariant(_newParameter != null);
}
/// <summary>
/// Visits the children of the <see cref="T:System.Linq.Expressions.MemberExpression"/>.
/// </summary>
/// <returns>
/// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
/// </returns>
/// <param name="node">The expression to visit.</param>
protected override Expression VisitMember(MemberExpression node)
{
var propertyMaps = _typeMap.GetPropertyMaps();
Contract.Assume(propertyMaps != null);
// Find any mapping for this member
var propertyMap = propertyMaps.SingleOrDefault(map => map.SourceMember == node.Member);
if (propertyMap == null)
return base.VisitMember(node);
var destinationProperty = propertyMap.DestinationProperty;
Contract.Assume(destinationProperty != null);
var destinationMember = destinationProperty.MemberInfo;
Contract.Assume(destinationMember != null);
// Check the new member is a property too
var property = destinationMember as PropertyInfo;
if (property == null)
return base.VisitMember(node);
// Access the new property
var newPropertyAccess = Expression.Property(_newParameter, property);
return base.VisitMember(newPropertyAccess);
}
}
Then implement an extension method to make this easier to use:
/// <summary>
/// A class which contains extension methods for <see cref="Expression"/> and <see cref="Expression{TDelegate}"/> instances.
/// </summary>
public static class ExpressionExtensions
{
/// <summary>
/// Remaps all property access from type <typeparamref name="TSource"/> to <typeparamref name="TDestination"/> in <paramref name="expression"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source element.</typeparam>
/// <typeparam name="TDestination">The type of the destination element.</typeparam>
/// <typeparam name="TResult">The type of the result from the lambda expression.</typeparam>
/// <param name="expression">The <see cref="Expression{TDelegate}"/> to remap the property access in.</param>
/// <returns>An <see cref="Expression{TDelegate}"/> equivalent to <paramref name="expression"/>, but applying to elements of type <typeparamref name="TDestination"/> instead of <typeparamref name="TSource"/>.</returns>
public static Expression<Func<TDestination, TResult>> RemapForType<TSource, TDestination, TResult>(this Expression<Func<TSource, TResult>> expression)
{
Contract.Requires(expression != null);
Contract.Ensures(Contract.Result<Expression<Func<TDestination, TResult>>>() != null);
var newParameter = Expression.Parameter(typeof (TDestination));
Contract.Assume(newParameter != null);
var visitor = new AutoMapVisitor<TSource, TDestination>(newParameter);
var remappedBody = visitor.Visit(expression.Body);
if (remappedBody == null)
throw new InvalidOperationException("Unable to remap expression");
return Expression.Lambda<Func<TDestination, TResult>>(remappedBody, newParameter);
}
}
This can subsequently be used like so (in an NUnit test):
[TestFixture]
public class RemappingTests
{
#region Setup/Teardown
/// <summary>
/// Sets up the variables before each test.
/// </summary>
[SetUp]
public void Setup()
{
var accountModelMap = Mapper.CreateMap<AccountModel, Account>();
Contract.Assume(accountModelMap != null);
accountModelMap.ForMember(account => account.Id, expression => expression.MapFrom(model => model.Id));
accountModelMap.ForMember(account => account.Balance, expression => expression.MapFrom(model => model.Bal));
accountModelMap.ForMember(account => account.CustomerName, expression => expression.MapFrom(model => model.Name));
}
[TearDown]
public void Teardown()
{
Mapper.Reset();
}
#endregion
/// <summary>
/// Checks that <see cref="ExpressionExtensions.RemapForType{TSource, TDestination, TResult}(Expression{Func{TSource, TResult}})"/> correctly remaps all property access for the new type.
/// </summary>
/// <param name="balance">The balance to use as the value for <see cref="Account.Balance"/>.</param>
/// <returns>Whether the <see cref="Account.Balance"/> was greater than 50.</returns>
[TestCase(0, Result = false)]
[TestCase(80, Result = true)]
public bool RemapperUsesPropertiesOfNewDataType(double balance)
{
Expression<Func<AccountModel, bool>> modelExpr = model => model.Bal > 50;
var accountExpr = modelExpr.RemapForType<AccountModel, Account, bool>();
var compiled = accountExpr.Compile();
Contract.Assume(compiled != null);
var hasBalance = compiled(new Account {Balance = balance});
return hasBalance;
}
}
In case that is too much code to find the exact call, here it is:
Expression<Func<AccountModel, bool>> modelExpr = model => model.Bal > 50;
var accountExpr = modelExpr.RemapForType<AccountModel, Account, bool>();
You can use an ExpressionVisitor to rewrite the Expression:
public class AccountModelRewriter : ExpressionVisitor
{
private Stack<ParameterExpression[]> _LambdaStack = new Stack<ParameterExpression[]>();
protected override Expression VisitLambda<T>(Expression<T> node)
{
var lambda = (LambdaExpression)node;
_LambdaStack.Push(
lambda.Parameters.Select(parameter => typeof(AccountModel) == parameter.Type ? Expression.Parameter(typeof(Account)) : parameter)
.ToArray()
);
lambda = Expression.Lambda(
this.Visit(lambda.Body),
_LambdaStack.Pop()
);
return lambda;
}
protected override Expression VisitMember(MemberExpression node)
{
var memberExpression = (MemberExpression)node;
var declaringType = memberExpression.Member.DeclaringType;
var propertyName = memberExpression.Member.Name;
if (typeof(AccountModel) == declaringType)
{
switch (propertyName)
{
case "Bal" :
propertyName = "Balance";
break;
case "Name" :
propertyName = "CustomerName";
break;
}
memberExpression = Expression.Property(
this.Visit(memberExpression.Expression),
typeof(Account).GetProperty(propertyName)
);
}
return memberExpression;
}
protected override Expression VisitParameter(ParameterExpression node)
{
node = (ParameterExpression)base.VisitParameter(node);
if (typeof(AccountModel) == node.Type)
{
node = this._LambdaStack.Peek().Single(parameter => parameter.Type == typeof(Account));
}
return node;
}
}
This visitor switches the input parameters from type AccountModel to Account (that's the VisitLambda and VisitParameter methods), and also changes all property accessors to use this new parameter as well as switching the property names if appropriate (that's the VisitMember part).
Usage is as follows:
Expression<Func<AccountModel, bool>> accountModelQuery = a => a.Bal == 0 && a.Name != null && a.Id != 7;
var accountQuery = (Expression<Func<Account, bool>>)new AccountModelRewriter().Visit(accountModelQuery);

Categories