Optimising code with a lot of "if" statements - c#

I want to optimise this code to reduce the number of if statements. Maybe it'd be better to use a lot of classes, and let the classes handle each required action?
It could be fabric pattern? Or is it OK to use 30+ similar if statements?
I've tried to make a Dictionary with string and object class. But I couldn't get it to work (or my skills are not good enough)
if (node[DATA_CONNECTION_ELEMENT] != null)
{
return new DataConnectionPropertyDataBinding(form, node[DATA_CONNECTION_ELEMENT], inputableEntity);
}
else if (node[FORM_PARAMETER_ELEMENT] != null)
{
return new FormParameterDataBinding(form, node[FORM_PARAMETER_ELEMENT], inputableEntity);
}
// + 30 more else ifs
else if (node[COMMAND_ELEMENT] != null)
{
return new CommandResultDataBinding(form, node[COMMAND_ELEMENT], inputableEntity);
}
else if (node[CONDITION_ELEMENT] != null)
{
return new ConditionDataBinding(form, node[CONDITION_ELEMENT], inputableEntity);
}
else if (node[CLIPBOARD_ELEMENT] != null)
{
return new ClipboardDataBinding(form, node[CLIPBOARD_ELEMENT], inputableEntity);
}
else
{
return new ConstantDataBinding(form, node);
}
Want to make it look something like
foreach (var item in allThatShareSomeInterface)
{
if (item.CanHandle(node.Atributes[0]))
{
return item.neededObject();
}
}
Here is the answer. How it really works.
Dictionary<string, Type> allObjects = new Dictionary<string, Type>();
allObjects.Add(CONDITION_ELEMENT, typeof(ConditionDataBinding));
allObjects.Add(DATA_TYPE_FORMAT_ELEMENT, typeof(DataTypeFormatDataBinding));
allObjects.Add(DATA_TYPE_CONVERT_ELEMENT, typeof(DataTypeConvertDataBinding));
allObjects.Add(FORM_PARAMETER_ELEMENT, typeof(FormParameterDataBinding));
allObjects.Add(FORM_ELEMENT, typeof(FormPropertyDataBinding));
allObjects.Add(STRING_ELEMENT, typeof(StringFormatDataBinding));
allObjects.Add(FORMULA_ELEMENT, typeof(FormulaDataBinding));
allObjects.Add(COMMAND_ELEMENT, typeof(CommandResultDataBinding));
// + many
foreach (var pair in allObjects)
{
if (node[pair.Key] != null)
{
ConstructorInfo ctor = pair.Value.GetConstructor(new[] { typeof(IWorkflowForm), typeof(XmlNode), typeof(IInputable) });
return ctor.Invoke(new object[] { form, node[pair.Key], inputableEntity });
}
}

You may be able to make this work using reflection. It's probably going to make your code a bit slower though.
It should look something like this (not tested):
var pairs = new Dictionary<string, Type>()
{
{
DATA_CONNECTION_ELEMENT, typeof(DataConnectionPropertyDataBinding)
},
{
FORM_PARAMETER_ELEMENT, typeof(FormParameterDataBinding)
}
};
foreach (var pair in pairs)
{
if (node[pair.Key] != null)
{
ConstructorInfo ctor = pair.Value.GetConstructor(new[] { typeof(object), typeof(object), typeof(object) });
return ctor.Invoke(new object[] { form, node[pair.Key], inputableEntity });
}
}

If you know what you are doing, and you indeed need that many binding classes, one way to solve that is custom attributes + reflection + runtime code generation. Here’s an example.
// Enum for element type. The order matters, it's the order in which input dictionary is tested.
enum eElement
{
DataConnection,
FormParameter,
}
// Custom attribute to mark bindings classes with.
class DataBindingAttribute : Attribute
{
public eElement element;
public DataBindingAttribute( eElement e ) { element = e; }
}
// Base class for bindings
abstract class BindingBase { }
// Couple test binding classes
[DataBinding( eElement.DataConnection )]
class DataConnectionPropertyDataBinding: BindingBase
{
public DataConnectionPropertyDataBinding( object data ) { }
}
[DataBinding( eElement.FormParameter )]
class FormParameterDataBinding: BindingBase
{
public readonly object data;
public FormParameterDataBinding( object data ) { this.data = data; }
}
// This static class does the magic.
static class BindingsFactory
{
// Key = eElement from custom attribute, value = function that constructs the binding. This example uses the constructor with single object argument.
// It's a good idea to use strong types for arguments instead.
static readonly SortedDictionary<eElement, Func<object, BindingBase>> dictTypes = new SortedDictionary<eElement, Func<object, BindingBase>>();
static BindingsFactory()
{
// Constructor argument types, just a single `object` in this example.
Type[] constructorArgumentTypes = new Type[ 1 ]
{
typeof( object )
};
ParameterExpression[] constructorArgumentExpressions = constructorArgumentTypes
.Select( tp => Expression.Parameter( tp ) )
.ToArray();
// Find all types in current assembly
var ass = Assembly.GetExecutingAssembly();
foreach( Type tp in ass.GetTypes() )
{
// Try to get the custom attribute
var dba = tp.GetCustomAttribute<DataBindingAttribute>();
if( null == dba )
continue;
// Ensure you don't have 2 classes with the same element ID value
Debug.Assert( !dictTypes.ContainsKey( dba.element ) );
// Ensure the found type inherits from BindingBase
Debug.Assert( typeof( BindingBase ).IsAssignableFrom( tp ) );
// Compile the function that constructs the new binding object
ConstructorInfo ci = tp.GetConstructor( constructorArgumentTypes );
Debug.Assert( null != ci );
// new Binding(...)
var expNew = Expression.New( ci, constructorArgumentExpressions );
// (BindingBase)( new Binding( ... ) )
var expCast = Expression.Convert( expNew, typeof( BindingBase ) );
// Compile into lambda
var lambda = Expression.Lambda<Func<object, BindingBase>>( expCast, constructorArgumentExpressions );
// Compile the lambda, and save in the sorted dictionary
var func = lambda.Compile();
dictTypes.Add( dba.element, func );
}
}
public static BindingBase tryConstruct( Dictionary<eElement, object> dict )
{
foreach( var kvp in dictTypes )
{
object arg;
if( !dict.TryGetValue( kvp.Key, out arg ) )
continue;
return kvp.Value( arg );
}
return null;
}
}
class Program
{
static void Main( string[] args )
{
var dict = new Dictionary<eElement, object>();
dict[ eElement.FormParameter ] = 12;
// This line will construct an instance of FormParameterDataBinding
var res = BindingsFactory.tryConstruct( dict );
}
}

Related

Load accessor Func by reflection into Dictionary

Background: the user should be able to as efficiently reasonable as possible choose a DB-Table/Model/Class and filter/sort/display all of the public properties of it.
The names can be queried by the reflection-API, but I wondered, if these accesses can be stored and become more efficient this way?
This example shows how it could be done, however on every access it'll query the reflection-api in the func.
public class TestClass // the Model or Table
{
public int Id { get; set; }
public string Name { get; set; }
}
public static void Main( string[] args )
{
var testClasses = new TestClass[] {
new TestClass { Id = 1 , Name = "1" } ,
new TestClass { Id = 2 , Name = "2" } ,
new TestClass { Id = 3 , Name = "3" } ,
};
var propertyInfos = typeof( TestClass ).GetProperties();
var map = new Dictionary<string,Func<object,object>>(); // Func<object,object> -> Func takes an instance of the class and return a public property
// load the map once
foreach( var propertyInfo in propertyInfos )
{
Func<object,object> func = x => propertyInfo.GetValue( x );
map.Add( propertyInfo.Name , func );
}
// get the names by user-input
var names = propertyInfos.Select( x => x.Name ).ToArray();
// load the properties by name
foreach( var testClass in testClasses )
{
Console.WriteLine( $"{testClass.Id} - {testClass.Name}" );
foreach( var name in names )
{
var func = map[ name ];
var value = func( testClass ); // this is 'bad' as it uses reflection every invokation
Console.WriteLine( $"\t{name} = {value}" );
}
}
}
My question would be: can this Dictionary
var map = new Dictionary<string,Func<object,object>> {
{ "Id" , x => ( x as TestClass ).Id } ,
{ "Name" , x => ( x as TestClass ).Name } ,
};
be created automatically by just providing the Type (and without using reflection on each invokation)?
You could gain something by removing the reflection from each call and doing it only once:
var par = Expression.Parameter(typeof(object), "row");
// load the map once
foreach (var propertyInfo in propertyInfos)
{
Func<object, object> func = Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Property(Expression.Convert(par, propertyInfo.DeclaringType), propertyInfo), typeof(object)), par).Compile();
map.Add(propertyInfo.Name, func);
}
I create a vary small expression tree that casts the parameter object to the "correct" type (TestClass in this case), calls the getter of the property and the convert the result to object.

How do you give a C# Auto-Property a default value using a custom attribute?

How do you give a C# Auto-Property a default value, using a custom attribute?
This is the code I want to see:
class Person
{
[MyDefault("William")]
public string Name { get; set; }
}
I am aware that there is no built in method to initialize the default using an attribute - can I write my own custom class that uses my custom attributes to initialize the default?
If you want to do it with PostSharp (as your tags suggest) then use a Lazy Loading aspect. You can see the one I built here http://programmersunlimited.wordpress.com/2011/03/23/postsharp-weaving-community-vs-professional-reasons-to-get-a-professional-license/
With an aspect you can apply default value to a single property or apply it to multiple properties with a single declaration at the class level.
Lazy loading aspect will use LocationInterceptionAspect base class.
[Serializable]
[LazyLoadingAspect(AttributeExclude=true)]
[MulticastAttributeUsage(MulticastTargets.Property)]
public class LazyLoadingAspectAttribute : LocationInterceptionAspect
{
public object DefaultValue {get; set;}
public override void OnGetValue(LocationInterceptionArgs args)
{
args.ProceedGetValue();
if (args.Value != null)
{
return;
}
args.Value = DefaultValue;
args.ProceedSetValue();
}
}
then apply the aspect like so
[LazyLoadingAspect(DefaultValue="SomeValue")]
public string MyProp { get; set; }
You could use a helper class like that:
public class DefaultValueHelper
{
public static void InitializeDefaultValues<T>(T obj)
{
var properties =
(from prop in obj.GetType().GetProperties()
let attr = GetDefaultValueAttribute(prop)
where attr != null
select new
{
Property = prop,
DefaultValue = attr.Value
}).ToArray();
foreach (var p in properties)
{
p.Property.SetValue(obj, p.DefaultValue, null);
}
}
private static DefaultValueAttribute GetDefaultValueAttribute(PropertyInfo prop)
{
return prop.GetCustomAttributes(typeof(DefaultValueAttribute), true)
.Cast<DefaultValueAttribute>()
.FirstOrDefault();
}
}
And call InitializeDefaultValues in the constructor of your class.
class Foo
{
public Foo()
{
DefaultValueHelper.InitializeDefaultValues(this);
}
[DefaultValue("(no name)")]
public string Name { get; set; }
}
EDIT: updated version, which generates and caches a delegate to do the initialization. This is to avoid using reflection every time the method is called for a given type.
public static class DefaultValueHelper
{
private static readonly Dictionary<Type, Action<object>> _initializerCache;
static DefaultValueHelper()
{
_initializerCache = new Dictionary<Type, Action<object>>();
}
public static void InitializeDefaultValues(object obj)
{
if (obj == null)
return;
var type = obj.GetType();
Action<object> initializer;
if (!_initializerCache.TryGetValue(type, out initializer))
{
initializer = MakeInitializer(type);
_initializerCache[type] = initializer;
}
initializer(obj);
}
private static Action<object> MakeInitializer(Type type)
{
var arg = Expression.Parameter(typeof(object), "arg");
var variable = Expression.Variable(type, "x");
var cast = Expression.Assign(variable, Expression.Convert(arg, type));
var assignments =
from prop in type.GetProperties()
let attr = GetDefaultValueAttribute(prop)
where attr != null
select Expression.Assign(Expression.Property(variable, prop), Expression.Constant(attr.Value));
var body = Expression.Block(
new ParameterExpression[] { variable },
new Expression[] { cast }.Concat(assignments));
var expr = Expression.Lambda<Action<object>>(body, arg);
return expr.Compile();
}
private static DefaultValueAttribute GetDefaultValueAttribute(PropertyInfo prop)
{
return prop.GetCustomAttributes(typeof(DefaultValueAttribute), true)
.Cast<DefaultValueAttribute>()
.FirstOrDefault();
}
}
If to speculate with Expressions you could make initializing delegates and cache them. It will make code much faster comparing with just pure reflection.
internal static class Initializer
{
private class InitCacheEntry
{
private Action<object, object>[] _setters;
private object[] _values;
public InitCacheEntry(IEnumerable<Action<object, object>> setters, IEnumerable<object> values)
{
_setters = setters.ToArray();
_values = values.ToArray();
if (_setters.Length != _values.Length)
throw new ArgumentException();
}
public void Init(object obj)
{
for (int i = 0; i < _setters.Length; i++)
{
_setters[i](obj, _values[i]);
}
}
}
private static Dictionary<Type, InitCacheEntry> _cache = new Dictionary<Type, InitCacheEntry>();
private static InitCacheEntry MakeCacheEntry(Type targetType)
{
var setters = new List<Action<object, object>>();
var values = new List<object>();
foreach (var propertyInfo in targetType.GetProperties())
{
var attr = (DefaultAttribute) propertyInfo.GetCustomAttributes(typeof (DefaultAttribute), true).FirstOrDefault();
if (attr == null) continue;
var setter = propertyInfo.GetSetMethod();
if (setter == null) continue;
// we have to create expression like (target, value) => ((TObj)target).setter((T)value)
// where T is the type of property and obj is instance being initialized
var targetParam = Expression.Parameter(typeof (object), "target");
var valueParam = Expression.Parameter(typeof (object), "value");
var expr = Expression.Lambda<Action<object, object>>(
Expression.Call(Expression.Convert(targetParam, targetType),
setter,
Expression.Convert(valueParam, propertyInfo.PropertyType)),
targetParam, valueParam);
var set = expr.Compile();
setters.Add(set);
values.Add(attr.DefaultValue);
}
return new InitCacheEntry(setters, values);
}
public static void Init(object obj)
{
Type targetType = obj.GetType();
InitCacheEntry init;
if (!_cache.TryGetValue(targetType, out init))
{
init = MakeCacheEntry(targetType);
_cache[targetType] = init;
}
init.Init(obj);
}
}
You could create a method like this:
public static void FillProperties<T>(T obj)
{
foreach (var property in typeof(T).GetProperties())
{
var attribute = property
.GetCustomAttributes(typeof(DefaultValueAttribute), true)
.Cast<DefaultValueAttribute>()
.SingleOrDefault();
if (attribute != null)
property.SetValue(obj, attribute.Value, null);
}
}
You can then either use a factory method that calls this method or call it directly from the constructor. Note that this usage of reflection is probably not a good idea if you create a lot of objects this way and performance is important.

Lookup property in object graph via a string

I'm trying to access various parts of a nested class structure using a arbitrary string.
Given the following (contrived) classes:
public class Person
{
public Address PersonsAddress { get; set; }
}
public class Adddress
{
public PhoneNumber HousePhone { get; set; }
}
public class PhoneNumber
{
public string Number { get; set; }
}
I'd like to be able to get the object at "PersonsAddress.HousePhone.Number" from an instance of the Person object.
Currently I'm doing some funky recursive lookup using reflection, but I'm hoping that some ninjas out there have some better ideas.
For reference, here is the (crappy) method I've developed:
private static object ObjectFromString(object basePoint, IEnumerable<string> pathToSearch)
{
var numberOfPaths = pathToSearch.Count();
if (numberOfPaths == 0)
return null;
var type = basePoint.GetType();
var properties = type.GetProperties();
var currentPath = pathToSearch.First();
var propertyInfo = properties.FirstOrDefault(prop => prop.Name == currentPath);
if (propertyInfo == null)
return null;
var property = propertyInfo.GetValue(basePoint, null);
if (numberOfPaths == 1)
return property;
return ObjectFromString(property, pathToSearch.Skip(1));
}
You could simply use the standard .NET DataBinder.Eval Method, like this:
object result = DataBinder.Eval(myPerson, "PersonsAddress.HousePhone.Number");
I've had to some something similar in the past. I went with the lambda approach because after compiling them I can cache them. I've removed the caching in this code.
I included a few unit tests to show the usage of the method. I hope this is helpful.
private static object GetValueForPropertyOrField( object objectThatContainsPropertyName, IEnumerable<string> properties )
{
foreach ( var property in properties )
{
Type typeOfCurrentObject = objectThatContainsPropertyName.GetType();
var parameterExpression = Expression.Parameter( typeOfCurrentObject, "obj" );
Expression memberExpression = Expression.PropertyOrField( parameterExpression, property );
var expression = Expression.Lambda( Expression.GetDelegateType( typeOfCurrentObject, memberExpression.Type ), memberExpression, parameterExpression ).Compile();
objectThatContainsPropertyName = expression.DynamicInvoke( objectThatContainsPropertyName );
}
return objectThatContainsPropertyName;
}
[TestMethod]
public void TestOneProperty()
{
var dateTime = new DateTime();
var result = GetValueForPropertyOrField( dateTime, new[] { "Day" } );
Assert.AreEqual( dateTime.Day, result );
}
[TestMethod]
public void TestNestedProperties()
{
var dateTime = new DateTime();
var result = GetValueForPropertyOrField( dateTime, new[] { "Date", "Day" } );
Assert.AreEqual( dateTime.Date.Day, result );
}
[TestMethod]
public void TestDifferentNestedProperties()
{
var dateTime = new DateTime();
var result = GetValueForPropertyOrField( dateTime, new[] { "Date", "DayOfWeek" } );
Assert.AreEqual( dateTime.Date.DayOfWeek, result );
}
Here's a non-recursive version with (almost) the same semantics:
private static object ObjectFromString(object basePoint, IEnumerable<string> pathToSearch)
{
var value = basePoint;
foreach (var propertyName in pathToSearch)
{
var property = value.GetType().GetProperty(propertyName);
if (property == null) return null;
value = property.GetValue(value, null);
}
return value;
}
Since you are already interested in resolving string property paths, you may benefit from looking into the Dynamic LINQ query library posted as an example by Scott Guthrie # Microsoft. It parses your string expressions and produces express trees that can be compiled and cached as suggested by #Brian Dishaw.
This would provide you with a wealth of additional options by providing a simple and robust expression syntax you can use in your configuration approach. It supports the common LINQ methods on enumerables, plus simple operator logic, math calculations, property path evaluation, etc.
this is based on Brian's code, did some modification to support index addressing for List:
private static object GetValueForPropertyOrField( object objectThatContainsPropertyName, IEnumerable<string> properties )
{
foreach ( var property in properties )
{
Type typeOfCurrentObject = objectThatContainsPropertyName.GetType();
var parameterExpression = Expression.Parameter( typeOfCurrentObject, "obj" );
var arrayIndex = property.IndexOf('[');
if ( arrayIndex > 0)
{
var property1 = property.Substring(0, arrayIndex);
Expression memberExpression1 = Expression.PropertyOrField( parameterExpression, property1 );
var expression1 = Expression.Lambda( Expression.GetDelegateType( typeOfCurrentObject, memberExpression1.Type ), memberExpression1, parameterExpression ).Compile();
objectThatContainsPropertyName = expression1.DynamicInvoke( objectThatContainsPropertyName );
var index = Int32.Parse(property.Substring(arrayIndex+1, property.Length-arrayIndex-2));
typeOfCurrentObject = objectThatContainsPropertyName.GetType();
parameterExpression = Expression.Parameter( typeOfCurrentObject, "list" );
Expression memberExpression2 = Expression.Call(parameterExpression, typeOfCurrentObject.GetMethod("get_Item"), new Expression[] {Expression.Constant(index)});
var expression2 = Expression.Lambda( Expression.GetDelegateType( typeOfCurrentObject, memberExpression2.Type ), memberExpression2, parameterExpression ).Compile();
objectThatContainsPropertyName = expression2.DynamicInvoke( objectThatContainsPropertyName );
}
else
{
Expression memberExpression = Expression.PropertyOrField( parameterExpression, property );
var expression = Expression.Lambda( Expression.GetDelegateType( typeOfCurrentObject, memberExpression.Type ), memberExpression, parameterExpression ).Compile();
objectThatContainsPropertyName = expression.DynamicInvoke( objectThatContainsPropertyName );
}
}

Initialize an object of type T from Dictionary<string,object>

I'm looking for more generic/"standard" way to instantiate object of some type T from set of pairs string,object. For me it looks like there should be some well known way to do it but I cannot find it, so I come up with this piece of code.
Does anybody know something better?
// usage
public class test
{
public int field1;
public string field2;
public bool field3;
public string[] field4;
public IDictionary<string,object> field5 { get; set; }
public static IDictionary<string,object> dynamic()
{
return new Dictionary<string,object>{
{ "field1", 2 },
{ "field2", "string" },
{ "field3", true },
{ "field4", new[] { "id3", "id4", "id5" } },
{ "field5", new Dictionary<string,object>{ { "id1", "" } } }
};
}
}
...
var r = new dynamic_data_serializer<test>().create( test.dynamic() );
...
//
public class dynamic_data_serializer< T >
{
public T create( object obj )
{
var result = default(T);
if ( obj == null )
return result;
var ttype = typeof(T);
var objtype = obj.GetType();
if ( ttype.IsAssignableFrom( objtype ) ) {
result = (T)obj;
return result;
}
if ( ttype.IsClass ) { // custom classes, array, dictionary, etc.
result = Activator.CreateInstance<T>();
if ( objtype == typeof(IDictionary<string,object>) ||
objtype == typeof(Dictionary<string,object>) ) {
var obj_as_dict = obj as IDictionary<string,object>;
var fields = ttype.GetFields();
if ( fields.Length > 0 )
set_fields_from( result, fields, obj_as_dict );
var properties = ttype.GetProperties();
if ( properties.Length > 0 )
set_properties_from( result, properties, obj_as_dict );
}
}
return result;
}
private void set_fields_from( T _this_, FieldInfo[] fields, IDictionary<string,object> obj ) {
foreach ( var fld in fields ) {
var v = find( obj, fld.Name );
if ( v != null ) {
var mobj = call_deserialize( fld.FieldType, v );
fld.SetValue( _this_, mobj );
}
}
}
private void set_properties_from( T _this_, PropertyInfo[] properties, IDictionary<string,object> obj ) {
foreach ( var prop in properties ) {
var v = find( obj, prop.Name );
if ( v != null ) {
var mobj = call_deserialize( prop.PropertyType, v );
prop.SetValue( _this_, mobj, null );
}
}
}
private object find( IDictionary<string,object> obj, string name ) {
foreach ( var kv in obj )
if ( string.Compare( kv.Key, name, true ) == 0 )
return kv.Value;
return null;
}
private object call_deserialize( Type des_type, object value ) {
var gtype = typeof(dynamic_data_serializer<>);
Type desz_type = gtype.MakeGenericType( new[]{ des_type } );
object desz = Activator.CreateInstance( desz_type );
var method_type = desz_type.GetMethod( "create" );
return method_type.Invoke( desz, new[]{ value } );
}
}
}
DataContractJsonSerializer is too slow, but you're using reflection? If you have to deserialize lots of objects, I would recommend using compiled lambdas instead of reflection. A lambda can only set properties, not fields (at least in .Net 3.5), so you may have to adjust the classes you use it on, but it's worth it because it's like 1000 times faster.
Here's a function that creates a property setter given a type and a PropertyInfo for the property to set:
static Action<object, TValue> MakeSetter<TValue>(Type tclass, PropertyInfo propInfo)
{
var t = lambda.Expression.Parameter(typeof(object), "t");
var v = lambda.Expression.Parameter(typeof(TValue), "v");
// return (t, v) => ((tclass)t).prop = (tproperty)v
return (Action<object, TValue>)
lambda.Expression.Lambda(
lambda.Expression.Call(
lambda.Expression.Convert(t, tclass),
propInfo.GetSetMethod(),
lambda.Expression.Convert(v, propInfo.PropertyType)),
t,
v)
.Compile();
}
You would have a dictionary of setters for each class, and whenever you have to set a property of a class, you would look up the setter for that property in the dictionary and call it with the value to assign, like this: setters[propName](_this_, value);
I might suggest FormatterServices.PopulateObjectMembers, except a: this is still slow AFAIK, and b: I tried it (below) and it seems to want to throw an exception on the property (don't know why; didn't look too deep). Another option may be Expression, but you don't really want to do the Compile each time (better to do it once only and cache it, but that demands a known format).
public T create(object obj)
{ // simplified for illustration
var bindings = obj as IDictionary<string, object>;
Type type = typeof(T);
var func = Expression.Lambda<Func<T>>(Expression.MemberInit(
Expression.New(type),
from pair in bindings
let member = type.GetMember(pair.Key).Single()
select (MemberBinding)Expression.Bind(member, Expression.Constant(pair.Value))));
return func.Compile().Invoke();
}
Finally, you might cache a set of pre-compiled Action<object> setters (keyed against the member name). In reality this is probably your best bet. Properties are easy (you use Delegate.CreateDelegate) - fields might need DynamicMethod - but if you can't predict the layout in advance it'll have the least overhead.
For the keyed / IL approach (you won't get faster):
public class dynamic_data_serializer<T>
{
public T create(object obj)
{
T inst = Activator.CreateInstance<T>();
var bindings = obj as IDictionary<string, object>;
foreach (var pair in bindings)
{
setters[pair.Key](inst, pair.Value);
}
return inst;
}
private static readonly Dictionary<string, Action<T, object>> setters;
static dynamic_data_serializer()
{
setters = new Dictionary<string, Action<T, object>>(StringComparer.Ordinal);
foreach (PropertyInfo prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
setters.Add(prop.Name, CreateForMember(prop));
}
foreach (FieldInfo field in typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance)) {
setters.Add(field.Name, CreateForMember(field));
}
}
static Action<T, object> CreateForMember(MemberInfo member)
{
bool isField;
Type type;
switch (member.MemberType) {
case MemberTypes.Property:
isField = false;
type = ((PropertyInfo)member).PropertyType;
break;
case MemberTypes.Field:
isField = true;
type = ((FieldInfo)member).FieldType;
break;
default:
throw new NotSupportedException();
}
DynamicMethod method = new DynamicMethod("__set_" + member.Name, null, new Type[] { typeof(T), typeof(object) });
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
if(type != typeof(object)) {
il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
}
if (isField) {il.Emit(OpCodes.Stfld, (FieldInfo)member);}
else { il.EmitCall(OpCodes.Callvirt, ((PropertyInfo)member).GetSetMethod(), null); }
il.Emit(OpCodes.Ret);
return (Action<T, object>)method.CreateDelegate(typeof(Action<T, object>));
}
}
DataContractJsonSerializer
Why would you make a custom serializer and not use the DataContractJsonSerializer?
EDIT
If DataContractJsonSerializer doesn't fit you, you can try JSON.Net. Implementing a serializer efficiently is not an easy task, there's a lot of pitfalls and special cases that you may not want to get into. By the way, your code sample makes heavy use of reflection which is slow, I doubt that it will perform better than DataContractJsonSerializer or JSON.Net.

Expression to Call a Method on Each Property of a Class

I want to take a class, loop through it's properties, get the property value, and call a method passing that property value in. I think I can get the property values, but what does the lambda expression's body look like? What body is used to call a method on each property?
This is what I have so far...
Action<T> CreateExpression<T>( T obj )
{
foreach( var property in typeof( T ).GetProperties() )
{
Expression value = Expression.Property( Expression.Constant( obj ), property );
var method = Expression.Call( typeof( SomeType ), "SomeMethod", null, value );
}
// What expression body can be used that will call
// all the method expressions for each property?
var body = Expression...
return Expression.Lambda<Action<T>>( body, ... ).Compile();
}
It depends on a few things.
does the method return anything? Expression in 3.5 can't do multiple separate "action" operations (a statement body), but you can cheat if you can do something with a fluent API:
SomeMethod(obj.Prop1).SomeMethod(obj.Prop2).SomeMethod(obj.Prop3);
(perhaps using generics to make it simpler)
do you have access to 4.0? In 4.0 there are additional Expression types allowing statement bodies and exactly what you ask for. I discuss some similar examples in an article here (look for Expression.Block, although this is based on a beta a while ago - it may have been renamed by now).
Alternative; since you are compiling to a delegate, consider that an Action<T> is multicast; you could build a set of simple operations, and combine them in the delegate; this would work in 3.5; for example:
using System;
using System.Linq.Expressions;
static class SomeType
{
static void SomeMethod<T>(T value)
{
Console.WriteLine(value);
}
}
class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
static class Program
{
static readonly Action<Customer> action = CreateAction<Customer>();
static void Main()
{
Customer cust = new Customer { Id = 123, Name = "Abc" };
action(cust);
}
static Action<T> CreateAction<T>()
{
Action<T> result = null;
var param = Expression.Parameter(typeof(T), "obj");
foreach (var property in typeof(T).GetProperties(
BindingFlags.Instance | BindingFlags.Public))
{
if (property.GetIndexParameters().Length > 0) continue;
var propVal = Expression.Property(param, property);
var call = Expression.Call(typeof(SomeType), "SomeMethod", new Type[] {propVal.Type}, propVal);
result += Expression.Lambda<Action<T>>(call, param).Compile();
}
return result;
}
}
I dont think it will be so easy using Expressions, in .NET 3.5 at least.
.NET 4 supports a block construct I believe.
I suggest using Reflection.Emit rather.
Here is a starting point (for fields but can be changed easily):
internal static T CreateDelegate<T>(this DynamicMethod dm) where T : class
{
return dm.CreateDelegate(typeof(T)) as T;
}
static Dictionary<Type, Func<object, Dictionary<string, object>>> fieldcache =
new Dictionary<Type, Func<object, Dictionary<string, object>>>();
static Dictionary<string, object> GetFields(object o)
{
var t = o.GetType();
Func<object, Dictionary<string, object>> getter;
if (!fieldcache.TryGetValue(t, out getter))
{
var rettype = typeof(Dictionary<string, object>);
var dm = new DynamicMethod(t.Name + ":GetFields",
rettype, new Type[] { typeof(object) }, t);
var ilgen = dm.GetILGenerator();
var instance = ilgen.DeclareLocal(t);
var dict = ilgen.DeclareLocal(rettype);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Castclass, t);
ilgen.Emit(OpCodes.Stloc, instance);
ilgen.Emit(OpCodes.Newobj, rettype.GetConstructor(Type.EmptyTypes));
ilgen.Emit(OpCodes.Stloc, dict);
var add = rettype.GetMethod("Add");
foreach (var field in t.GetFields(
BindingFlags.DeclaredOnly |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic))
{
if (!field.FieldType.IsSubclassOf(typeof(Component)))
{
continue;
}
ilgen.Emit(OpCodes.Ldloc, dict);
ilgen.Emit(OpCodes.Ldstr, field.Name);
ilgen.Emit(OpCodes.Ldloc, instance);
ilgen.Emit(OpCodes.Ldfld, field);
ilgen.Emit(OpCodes.Castclass, typeof(object));
ilgen.Emit(OpCodes.Callvirt, add);
}
ilgen.Emit(OpCodes.Ldloc, dict);
ilgen.Emit(OpCodes.Ret);
fieldcache[t] = getter = dm.CreateDelegate<Func<object,
Dictionary<string, object>>>();
}
return getter(o);
}
Use the Block statement. The code below for example writes out the names of all properties
static void WritePropertyNames()
{
TestObject lTestObject = new TestObject();
PropertyInfo[] lProperty = typeof(TestObject).GetProperties();
List<Expression> lExpressions = new List<Expression>();
MethodInfo lMethodInfo = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
lProperty.ForEach(x =>
{
ConstantExpression lConstant = Expression.Constant(x.Name);
MethodCallExpression lMethodCall = Expression.Call(lMethodInfo, lConstant);
lExpressions.Add(lMethodCall);
});
BlockExpression lBlock = Expression.Block(lExpressions);
LambdaExpression lLambda = Expression.Lambda<Action>(lBlock, null);
Action lWriteProperties = lLambda.Compile() as Action;
lWriteProperties();
}
Expression trees can only contain a single statement. To do what you are trying you would need to Expression.Lambda<>() in your loop, passing "method" as the body.
I believe this has changed in .NET Framework 4.0.
Andrew
If you're willing to have your method SomeType.SomeMethod accept an object[] then you can do something like this (note that indexers can not be handled here so we discard them):
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Test {
class SomeType {
public static void SomeMethod(object[] values) {
foreach (var value in values) {
Console.WriteLine(value);
}
}
}
class Program {
static Action<T> CreateAction<T>() {
ParameterExpression parameter = Expression.Parameter(
typeof(T),
"parameter"
);
List<Expression> properties = new List<Expression>();
foreach (var info in typeof(T).GetProperties()) {
// can not handle indexers
if(info.GetIndexParameters().Length == 0) {
Expression property = Expression.Property(parameter, info);
properties.Add(Expression.Convert(property, typeof(object)));
}
}
Expression call = Expression.Call(
typeof(SomeType).GetMethod("SomeMethod"),
Expression.NewArrayInit(typeof(object), properties)
);
return Expression.Lambda<Action<T>>(call, parameter).Compile();
}
static void Main(string[] args) {
Customer c = new Customer();
c.Name = "Alice";
c.ID = 1;
CreateAction<Customer>()(c);
}
}
class Customer {
public string Name { get; set; }
public int ID { get; set; }
}
}
Of course this will be easier in .NET 4.0 with the LoopExpression.

Categories