C# Reflection: Fastest Way to Update a Property Value? - c#

Is this the fastest way to update a property using reflection? Assume the property is always an int:
PropertyInfo counterPropertyInfo = GetProperty();
int value = (int)counterPropertyInfo.GetValue(this, null);
counterPropertyInfo.SetValue(this, value + 1, null);

I did some benchmarking here when you know the type arguments (a non generic approach wont be very different). CreateDelegate would be the fastest approach for a property if you can't directly access it. With CreateDelegate you get a direct handle to GetGetMethod and GetSetMethod of the PropertyInfo, hence reflection is not used every time.
public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}
public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}
// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
return Delegate.CreateDelegate(typeof(T), method) as T;
}
public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
var body = propertySelector.Body as MemberExpression;
if (body == null)
throw new MissingMemberException("something went wrong");
return body.Member as PropertyInfo;
}
So now you call:
TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);
Or even better you can encapsulate the logic in a dedicated class to have a get and set methods on it.
Something like:
public class Accessor<S>
{
public static Accessor<S, T> Create<T>(Expression<Func<S, T>> memberSelector)
{
return new GetterSetter<T>(memberSelector);
}
public Accessor<S, T> Get<T>(Expression<Func<S, T>> memberSelector)
{
return Create(memberSelector);
}
public Accessor()
{
}
class GetterSetter<T> : Accessor<S, T>
{
public GetterSetter(Expression<Func<S, T>> memberSelector) : base(memberSelector)
{
}
}
}
public class Accessor<S, T> : Accessor<S>
{
Func<S, T> Getter;
Action<S, T> Setter;
public bool IsReadable { get; private set; }
public bool IsWritable { get; private set; }
public T this[S instance]
{
get
{
if (!IsReadable)
throw new ArgumentException("Property get method not found.");
return Getter(instance);
}
set
{
if (!IsWritable)
throw new ArgumentException("Property set method not found.");
Setter(instance, value);
}
}
protected Accessor(Expression<Func<S, T>> memberSelector) //access not given to outside world
{
var prop = memberSelector.GetPropertyInfo();
IsReadable = prop.CanRead;
IsWritable = prop.CanWrite;
AssignDelegate(IsReadable, ref Getter, prop.GetGetMethod());
AssignDelegate(IsWritable, ref Setter, prop.GetSetMethod());
}
void AssignDelegate<K>(bool assignable, ref K assignee, MethodInfo assignor) where K : class
{
if (assignable)
assignee = assignor.CreateDelegate<K>();
}
}
Short and simple. You can carry around an instance of this class for every "class-property" pair you wish to get/set.
Usage:
Person p = new Person { Age = 23 };
var ageAccessor = Accessor<Person>(x => x.Age);
int age = ageAccessor[p]; //gets 23
ageAccessor[p] = 45; //sets 45
Bit bad use of indexers here, you may replace it with dedicated "Get" and "Set" methods, but very intuitive to me :)
To avoid having to specify type each time like,
var ageAccessor = Accessor<Person>(x => x.Age);
var nameAccessor = Accessor<Person>(x => x.Name);
var placeAccessor = Accessor<Person>(x => x.Place);
I made the base Accessor<> class instantiable, which means you can do
var personAccessor = new Accessor<Person>();
var ageAccessor = personAccessor.Get(x => x.Age);
var nameAccessor = personAccessor.Get(x => x.Name);
var placeAccessor = personAccessor.Get(x => x.Place);
Having a base Accessor<> class means you can treat them as one type, for eg,
var personAccessor = new Accessor<Person>();
var personAccessorArray = new Accessor<Person>[]
{
personAccessor.Get(x => x.Age),
personAccessor.Get(x => x.Name),
personAccessor.Get(x => x.Place);
};

You should look at FastMember (nuget, source code], it's really fast comparing to reflection.
I've tested these 3 implementations:
PropertyInfo.SetValue
PropertyInfo.SetMethod
FastMember
The benchmark needs a benchmark function:
static long Benchmark(Action action, int iterationCount, bool print = true)
{
GC.Collect();
var sw = new Stopwatch();
action(); // Execute once before
sw.Start();
for (var i = 0; i <= iterationCount; i++)
{
action();
}
sw.Stop();
if (print) System.Console.WriteLine("Elapsed: {0}ms", sw.ElapsedMilliseconds);
return sw.ElapsedMilliseconds;
}
A fake class:
public class ClassA
{
public string PropertyA { get; set; }
}
Some test methods:
private static void Set(string propertyName, string value)
{
var obj = new ClassA();
obj.PropertyA = value;
}
private static void FastMember(string propertyName, string value)
{
var obj = new ClassA();
var type = obj.GetType();
var accessors = TypeAccessor.Create(type);
accessors[obj, "PropertyA"] = "PropertyValue";
}
private static void SetValue(string propertyName, string value)
{
var obj = new ClassA();
var propertyInfo = obj.GetType().GetProperty(propertyName);
propertyInfo.SetValue(obj, value);
}
private static void SetMethodInvoke(string propertyName, string value)
{
var obj = new ClassA();
var propertyInfo = obj.GetType().GetProperty(propertyName);
propertyInfo.SetMethod.Invoke(obj, new object[] { value });
}
The script itself:
var iterationCount = 100000;
var propertyName = "PropertyA";
var value = "PropertyValue";
Benchmark(() => Set(propertyName, value), iterationCount);
Benchmark(() => FastMember(propertyName, value), iterationCount);
Benchmark(() => SetValue(propertyName, value), iterationCount);
Benchmark(() => SetMethodInvoke(propertyName, value), iterationCount);
Results for 100 000 iterations:
Default setter : 3ms
FastMember: 36ms
PropertyInfo.SetValue: 109ms
PropertyInfo.SetMethod: 91ms
Now you can choose yours !!!

Just be sure that you are caching the PropertyInfo somehow, so that you aren't repeatably calling type.GetProperty. Other than that it would probably be faster if you created a delegate to a method on the type that performed the increment, or like Teoman suggested make the type implement an interface and use that.

Related

How do I make anonymous class implementing an interface with std only?

Here is a sample Scala code that I'm trying to rewrite in C#:
trait FuncHolder[T, TResult] {
def Value: Function1[T, TResult]
}
object FuncHolder {
def GetFunctionHolder[T, TResult](func: Function1[T, TResult]) = new FuncHolder[T, TResult] {
override def Value: Function1[T, TResult] = func
}
}
Here is where I started:
public abstract class FuncHolder<T, TResult>
{
public Func<T, TResult> Value { get; }
protected FuncHolder(Func<T, TResult> value)
{
Value = value;
}
}
public static class FuncHolder
{
public static FuncHolder<T, TResult> GetFuncHolder<T, TResult>(Func<T, TResult> func)
{
var ilBody = func.Method.GetMethodBody().GetILAsByteArray();
}
}
But then I stuck because I'm not sure if I could just copy that byte array in il.emit and it will work. So I thought maybe in 2019 there could be some ways in acheiving it without dirty magic, postsharping output binaries or something. I'm looking for a pure solution in terms of BCL and Expressions/DynamicMethods.
The most recent attempt is following:
public abstract class FuncHolder<T, TResult>
{
public abstract TResult GetResult(T value);
}
public static class FuncHolder
{
private static ModuleBuilder _builder = AssemblyBuilder
.DefineDynamicAssembly(new AssemblyName("OmsCodegen"), AssemblyBuilderAccess.Run)
.DefineDynamicModule("MainModule");
/// <summary>
/// Returns a holder that allows safely pass delegates through the network
/// </summary>
/// <param name="func">Func to hold. Note that it must be pure function, closure with external dependencies will fail</param>
public static FuncHolder<T, TResult> GetFuncHolder<T, TResult>(Func<T, TResult> func)
{
var tb = _builder.DefineType($"<{func.Method.MetadataToken}>__FuncHolder", TypeAttributes.Class | TypeAttributes.Sealed);
tb.SetParent(typeof(FuncHolder));
var baseMethod = typeof(FuncHolder<,>).GetMethod("GetResult");
Debug.Assert(baseMethod != null);
var implementation = tb.DefineMethod(baseMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual);
CopyIl(implementation, func.Method);
tb.DefineMethodOverride(implementation, baseMethod);
tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName);
return (FuncHolder<T, TResult>) Activator.CreateInstance(tb.CreateTypeInfo().AsType());
}
private static void CopyIl(MethodBuilder implementation, MethodInfo methodInfo)
{
var ilGenerator = implementation.GetILGenerator();
var methodBody = methodInfo.GetMethodBody();
var il = methodBody?.GetILAsByteArray() ?? throw new InvalidOperationException("Cannot get method body");
foreach (var local in methodBody.LocalVariables)
ilGenerator.DeclareLocal(local.LocalType);
var opCodes = GetOpCodes(il);
for (int i = 0; i < opCodes.Length; ++i)
{
if (!opCodes[i].code.HasValue)
continue;
OpCode opCode = opCodes[i].code.Value;
if (opCode.OperandType == OperandType.InlineBrTarget)
{
ilGenerator.Emit(opCode, BitConverter.ToInt32(il, i + 1));
i += 4;
continue;
}
if (opCode.OperandType == OperandType.ShortInlineBrTarget)
{
ilGenerator.Emit(opCode, il[i + 1]);
++i;
continue;
}
if (opCode.OperandType == OperandType.InlineType)
{
Type tp = methodInfo.Module.ResolveType(BitConverter.ToInt32(il, i + 1), methodInfo.DeclaringType.GetGenericArguments(), methodInfo.GetGenericArguments());
ilGenerator.Emit(opCode, tp);
i += 4;
continue;
}
if (opCode.FlowControl == FlowControl.Call)
{
MethodInfo mi = methodInfo.Module.ResolveMethod(BitConverter.ToInt32(il, i + 1)) as MethodInfo;
if (mi == methodInfo)
ilGenerator.Emit(opCode, implementation);
else
ilGenerator.Emit(opCode, mi);
i += 4;
continue;
}
ilGenerator.Emit(opCode);
}
}
static OpCodeContainer[] GetOpCodes(byte[] data)
{
List<OpCodeContainer> opCodes = new List<OpCodeContainer>();
foreach (byte opCodeByte in data)
opCodes.Add(new OpCodeContainer(opCodeByte));
return opCodes.ToArray();
}
class OpCodeContainer
{
public OpCode? code;
byte data;
public OpCodeContainer(byte opCode)
{
data = opCode;
try
{
code = (OpCode)typeof(OpCodes).GetFields().First(t => ((OpCode)(t.GetValue(null))).Value == opCode).GetValue(null);
}
catch
{
// if it throws an exception then code should remain null
}
}
}
}
Which fails with CLR execution error.
It's not exactly what I wanted but it's the only solution I came with
public abstract class FuncHolder<T, TResult>
{
[JsonIgnore]
public abstract Func<T, TResult> Value { get; }
}
public static class FuncHolder
{
private static Dictionary<int, object> _metadataTokenToMethodDictionary = new Dictionary<int, object>();
private class FuncHolderImplementation<T, TResult> : FuncHolder<T, TResult>
{
public int MetadataToken { get; }
public FuncHolderImplementation(int metadataToken)
{
MetadataToken = metadataToken;
}
public override Func<T, TResult> Value => (Func<T, TResult>)_metadataTokenToMethodDictionary[MetadataToken];
}
public static FuncHolder<T, TResult> GetFuncHolder<T, TResult>(Func<T, TResult> func)
{
if (!_metadataTokenToMethodDictionary.ContainsKey(func.Method.MetadataToken))
{
_metadataTokenToMethodDictionary[func.Method.MetadataToken] = func;
}
return new FuncHolderImplementation<T, TResult>(func.Method.MetadataToken);
}
}
Instead of wrapping a function in the type I merely pass a metadataToken which I then convert back.
Why is this needed may be shown as following:
var holder = FuncHolder.GetFuncHolder<string, int>(s => s.Length);
var settings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All};
var json = JsonConvert.SerializeObject(holder, settings);
var holder2 = JsonConvert.DeserializeObject<FuncHolder<string, int>>(json, settings);
Console.WriteLine(holder2.Value("hello"));
As you can see, this way function callback may be serialized and deserialized back.

c#: Call boxed delegate

In my project I need to transform data between several classes so I created a class DataMapper that is used for strong-typed mapping of properties from two different classes. When properties in the pair need to be modified I store two delegates (converters) for this purpose.
Then the DataMapper has two methods Update(T source, S target) and Update(S source, T target) that use these mappings to provide the tranformation.
public class DataMapper<TSourceType, TTargetType> : IDataUpdater<TSourceType, TTargetType> {
private readonly IDictionary<PropertyInfo, PropertyInfo> _sourceToTargetMap = new Dictionary<PropertyInfo, PropertyInfo>();
private readonly IDictionary<PropertyInfo, object> _converters = new Dictionary<PropertyInfo, object>();
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr)
{
_sourceToTargetMap.Add(sourcePropExpr.AsPropertyInfo(), targetPropExpr.AsPropertyInfo());
return this;
}
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr,
Func<TSourceValue, TTargetValue> sourceToTargetConverter,
Func<TTargetValue, TSourceValue> targetToSourceConverter)
{
_sourceToTargetMap.Add(sourcePropExpr.AsPropertyInfo(), targetPropExpr.AsPropertyInfo());
_converters.Add(sourcePropExpr.AsPropertyInfo(), sourceToTargetConverter);
_converters.Add(targetPropExpr.AsPropertyInfo(), targetToSourceConverter);
return this;
}
public void Update(TSourceType source, TTargetType target) {
foreach (var keyValuePair in _sourceToTargetMap) {
var sourceProp = keyValuePair.Key;
var targetProp = keyValuePair.Value;
Update(source, target, sourceProp, targetProp);
}
}
public void Update(TTargetType source, TSourceType target) {
foreach (var keyValuePair in _sourceToTargetMap) {
var sourceProp = keyValuePair.Value;
var targetProp = keyValuePair.Key;
Update(source, target, sourceProp, targetProp);
}
}
private void Update(
object source,
object target,
PropertyInfo sourceProperty,
PropertyInfo targetProperty)
{
var sourceValue = sourceProperty.GetValue(source);
if (_converters.ContainsKey(sourceProperty)) {
sourceValue = typeof(InvokeHelper<,>)
.MakeGenericType(sourceProperty.PropertyType, targetProperty.PropertyType)
.InvokeMember("Call", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, new[] { _converters[sourceProperty], sourceValue });
}
targetProperty.SetValue(target, sourceValue);
}
}
Here is the usage:
public SomeClass {
private static readonly IDataUpdater<SomeClass, SomeOtherClass> _dataMapper = new DataMapper<SomeClass, SomeOtherClass>()
.Map(x => x.PropertyA, y => y.PropertyAA)
.Map(x => x.PropertyB, y => y.PropertyBB, x => Helper.Encrypt(x), y => Helper.Decrypt(y));
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public void LoadFrom(SomeOtherClass source) {
_dataMapper.Update(source, this);
}
public void SaveTo(SomeOtherClass target) {
_dataMapper.Update(this, target);
}
}
You can see in class DataHelper in the last overload of method Update that when I want to call the stored converter function, I use helper class InvokeHelper, because I didn't found other way how to call boxed delegate Func. Code for class InvokeHelper is simple - just single static method:
public static class InvokeHelper<TSource, TTarget> {
public static TTarget Call(Func<TSource, TTarget> converter, TSource source) {
return converter(source);
}
}
Is there a way how to do it without reflection? I need to optimalize these transformations for speed.
Thanks.
You can use Delegate.DynamicInvoke to invoke the delegate. Or, use dynamic:
((dynamic)(Delegate)_converters[sourceProperty])(sourceValue);
The (Delegate) cast is not necessary. It's for documentation and runtime assertion purposes. Leave it out if you don't like it.
Actually, you better use delegate instead of object in the dictionary.
If it were me, I would use a little meta-coding with expressions to create a list of compiled and strongly typed delegates. When you call the Update method, you can go through each Action in the list and update the destination from the source.
No reflection and all of the compiling and such is done once, ahead of the Update call.
public class DataMapper<TSourceType, TTargetType> : IDataUpdater<TSourceType, TTargetType>
{
List<Action<TSourceType, TTargetType>> _mappers = new List<Action<TSourceType, TTargetType>>();
DataMapper<TTargetType, TSourceType> _reverseMapper;
public DataMapper() : this(false) { }
public DataMapper(bool isReverse)
{
if (!isReverse)
{
_reverseMapper = new DataMapper<TTargetType, TSourceType>(isReverse: true);
}
}
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr)
{
var mapExpression = Expression.Assign(targetPropExpr.Body, sourcePropExpr.Body);
_mappers.Add(
Expression.Lambda<Action<TSourceType, TTargetType>>(
mapExpression,
sourcePropExpr.Parameters[0],
targetPropExpr.Parameters[0])
.Compile());
if (_reverseMapper != null) _reverseMapper.Map(targetPropExpr, sourcePropExpr);
return this;
}
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr,
Func<TSourceValue, TTargetValue> sourceToTargetConverter,
Func<TTargetValue, TSourceValue> targetToSourceConverter)
{
var convertedSourceExpression = Expression.Invoke(Expression.Constant(sourceToTargetConverter), sourcePropExpr.Body);
var mapExpression = Expression.Assign(targetPropExpr.Body, convertedSourceExpression);
_mappers.Add(
Expression.Lambda<Action<TSourceType, TTargetType>>(
mapExpression,
sourcePropExpr.Parameters[0],
targetPropExpr.Parameters[0])
.Compile());
if (_reverseMapper != null) _reverseMapper.Map(targetPropExpr, sourcePropExpr, targetToSourceConverter, sourceToTargetConverter);
return this;
}
public void Update(TSourceType source, TTargetType target)
{
foreach (var mapper in _mappers)
{
mapper(source, target);
}
}
public void Update(TTargetType source, TSourceType target)
{
if (_reverseMapper != null)
{
_reverseMapper.Update(source, target);
}
else
{
throw new Exception("Reverse mapper is null. Did you reverse twice?");
};
}
}
The expression is built by taking the expressions that are passed in and using them as parts for the new expression.
Say you called .Map(x => x.PropertyA, y => y.PropertyAA). You now have 2 expressions each with a parameter x and y and each with a body x.PropertyA and y.PropertyAA.
Now you want to re-assemble these expression parts into an assignment expression like y.PropertyAA = x.PropertyA. This is done in the line var mapExpression = Expression.Assign(targetPropExpr.Body, sourcePropExpr.Body); which gives you an expected expression.
Now when you call Expression.Lambda, you are incorporating the parameters (x,y) into a new expression that looks like (x,y) = > y.PropertyAA = x.PropertyA.
Before you can execute this, you need to compile it, hence the .Compile(). But since you only need to compile this once for any given map, you can compile and store the result. The uncompiled expression is of type Expression<Action<TSourceType,TTargetType>> and after it is compiled the resulting type is Action<TSourceType,TTargetType>

List of assignment expressions

I've bending my mind for a while, but I think I'm missing something, so may be someone will help.
Let's say I have following mapper class:
public class Mapping<TSource, TResult>
{
private readonly Action<TSource, TResult> setter;
public Mapping(Expression<Func<TSource, TResult>> expression)
{
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda<Action<TSource, TResult>>(body, expression.Parameters[0], newValue);
setter = assign.Compile();
}
public void Assign(TSource instance, TResult value)
{
setter(instance, value);
}
}
And it is working fine:
[Test]
public void ShouldMapProperty()
{
var testClass = new TestClass();
var nameMapping = new Mapping<TestClass, string>(x => x.Name);
var ageMapping = new Mapping<TestClass, int>(x => x.Age);
nameMapping.Assign(testClass, "name");
ageMapping.Assign(testClass, 10);
Assert.AreEqual("name", testClass.Name);
Assert.AreEqual(10, testClass.Age);
}
Thing is, that I would like to keep mappings for single object type into some collection and TResult is getting in the way, as long as different properties have different types.
How to get rid of TResult nicely?
Update:
looks like I wasn't clear enough, so this would be sample how would I use it:
public class Mapping<TSource, TResult>
{
private readonly Action<TSource, TResult> setter;
private readonly string columnName;
public Mapping(Expression<Func<TSource, TResult>> expression, string columnName)
{
this.columnName = columnName;
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda<Action<TSource, TResult>>(body, expression.Parameters[0], newValue);
setter = assign.Compile();
}
public void Assign(TSource instance, DataRow row)
{
setter(instance, row[columnName]);
}
}
And then I would have some MappingConfiguration class, that would let me do this:
MappingConfiguration.For<TestClass>()
.Map(x => x.Name, "FirstName")
.Map(x => x.Age, "Age");
And finaly some MappingEngine class, that would take DataTable and MappingConfiguration as input and produce IEnumerable<TestClass> as output.
Update 2:
I've modified initial version to this:
public class Mapping2<TSource>
{
private readonly Delegate setter;
public Mapping2(Expression<Func<TSource, object>> expression)
{
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda(body, expression.Parameters[0], newValue);
setter = assign.Compile();
}
public void Assign(TSource instance, object value)
{
setter.DynamicInvoke(instance, value);
}
}
And it almost works.
By almost I mean it works with reference type properties, and with value type properties I get:
System.ArgumentException : Expression must be writeable
Parameter name: left
I've managed to do it, source code below. It runs somewhat faster than Automapper (not sure if my Automapper configuration is the fastest for this task), benchmark is not bulletproof, but on my machine to map 5 million rows took 20.16 seconds using my written mapper and 39.90 using Automapper, although it seems that Automapper uses less memory for this task (haven't measured it, but with 10 million rows Automapper gives result and my mapper fails with OutOfMemory).
public class MappingParameter<TSource>
{
private readonly Delegate setter;
private MappingParameter(Delegate compiledSetter)
{
setter = compiledSetter;
}
public static MappingParameter<TSource> Create<TResult>(Expression<Func<TSource, TResult>> expression)
{
var newValue = Expression.Parameter(expression.Body.Type);
var body = Expression.Assign(expression.Body, newValue);
var assign = Expression.Lambda(body, expression.Parameters[0], newValue);
var compiledSetter = assign.Compile();
return new MappingParameter<TSource>(compiledSetter);
}
public void Assign(TSource instance, object value)
{
object convertedValue;
if (!setter.Method.ReturnType.IsAssignableFrom(typeof(string)))
{
convertedValue = Convert.ChangeType(value, setter.Method.ReturnType);
}
else
{
convertedValue = value;
}
setter.DynamicInvoke(instance, convertedValue);
}
}
public class DataRowMappingConfiguration<TSource>
{
private readonly Dictionary<string, MappingParameter<TSource>> mappings =
new Dictionary<string, MappingParameter<TSource>>();
public DataRowMappingConfiguration<TSource> Add<TResult>(string columnName,
Expression<Func<TSource, TResult>> expression)
{
mappings.Add(columnName, MappingParameter<TSource>.Create(expression));
return this;
}
public Dictionary<string, MappingParameter<TSource>> Mappings
{
get
{
return mappings;
}
}
}
public class DataRowMapper<TSource>
{
private readonly DataRowMappingConfiguration<TSource> configuration;
public DataRowMapper(DataRowMappingConfiguration<TSource> configuration)
{
this.configuration = configuration;
}
public IEnumerable<TSource> Map(DataTable table)
{
var list = new List<TSource>(table.Rows.Count);
foreach (DataRow dataRow in table.Rows)
{
var obj = (TSource)Activator.CreateInstance(typeof(TSource));
foreach (var mapping in configuration.Mappings)
{
mapping.Value.Assign(obj, dataRow[mapping.Key]);
}
list.Add(obj);
}
return list;
}
}
public class TestClass
{
public string Name { get; set; }
public int Age { get; set; }
}
[TestFixture]
public class DataRowMappingTests
{
[Test]
public void ShouldMapPropertiesUsingOwnMapper()
{
var mappingConfiguration = new DataRowMappingConfiguration<TestClass>()
.Add("firstName", x => x.Name)
.Add("age", x => x.Age);
var mapper = new DataRowMapper<TestClass>(mappingConfiguration);
var dataTable = new DataTable();
dataTable.Columns.Add("firstName");
dataTable.Columns.Add("age");
for (int i = 0; i < 5000000; i++)
{
var row = dataTable.NewRow();
row["firstName"] = "John";
row["age"] = 15;
dataTable.Rows.Add(row);
}
var start = DateTime.Now;
var result = mapper.Map(dataTable).ToList();
Console.WriteLine((DateTime.Now - start).TotalSeconds);
Assert.AreEqual("John", result.First().Name);
Assert.AreEqual(15, result.First().Age);
}
[Test]
public void ShouldMapPropertyUsingAutoMapper()
{
Mapper.CreateMap<DataRow, TestClass>()
.ForMember(x => x.Name, x => x.MapFrom(y => y["firstName"]))
.ForMember(x => x.Age, x => x.MapFrom(y => y["age"]));
var dataTable = new DataTable();
dataTable.Columns.Add("firstName");
dataTable.Columns.Add("age");
for (int i = 0; i < 5000000; i++)
{
var row = dataTable.NewRow();
row["firstName"] = "John";
row["age"] = 15;
dataTable.Rows.Add(row);
}
var start = DateTime.Now;
var result = dataTable.Rows.OfType<DataRow>().Select(Mapper.Map<DataRow, TestClass>).ToList();
Console.WriteLine((DateTime.Now - start).TotalSeconds);
Assert.AreEqual("John", result.First().Name);
Assert.AreEqual(15, result.First().Age);
}
}
Something like thid maybe :
public class Mapping<TSource>
{
public void Assign<TResult>(TSource instance, TResult value)
{
var property = typeof(TSource).GetProperties().FirstOrDefault(p => p.PropertyType == typeof(TResult)));
if (property != null)
{
property.SetValue(instance, value, new object[0]);
}
}
}
But your object need to have ONE property of each type for this to be accurate
We could even make it more generic, but more dangerous :
public void Assign<TResult>(TSource instance, TResult value)
{
var property = typeof(TSource).GetProperties().FirstOrDefault(p => p.PropertyType.IsAssignableFrom(typeof(TResult)));
if (property != null)
{
property.SetValue(instance, value, new object[0]);
}
}
(this won't work if you have 2 properties inheriting from the same base class)...

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.

Linq expressions and extension methods to get property name

I was looking at this post that describes a simple way to do databinding between POCO properties: Data Binding POCO Properties
One of the comments by Bevan included a simple Binder class that can be used to accomplish such data binding. It works great for what I need but I would like to implement some of the suggestions that Bevan made to improve the class, namely:
Checking that source and target are
assigned
Checking that the properties
identified by sourcePropertyName and
targetPropertyName exist
Checking for type compatibility
between the two properties
Also, given that specifying properties by string is error prone, you could use Linq expressions and extension methods instead. Then instead of writing
Binder.Bind( source, "Name", target, "Name")
you could write
source.Bind( Name => target.Name);
I'm pretty sure I can handle the first three (though feel free to include those changes) but I have no clue how to use Linq expressions and extension methods to be able to write code without using property name strings.
Any tips?
Here is the original code as found in the link:
public static class Binder
{
public static void Bind(
INotifyPropertyChanged source,
string sourcePropertyName,
INotifyPropertyChanged target,
string targetPropertyName)
{
var sourceProperty
= source.GetType().GetProperty(sourcePropertyName);
var targetProperty
= target.GetType().GetProperty(targetPropertyName);
source.PropertyChanged +=
(s, a) =>
{
var sourceValue = sourceProperty.GetValue(source, null);
var targetValue = targetProperty.GetValue(target, null);
if (!Object.Equals(sourceValue, targetValue))
{
targetProperty.SetValue(target, sourceValue, null);
}
};
target.PropertyChanged +=
(s, a) =>
{
var sourceValue = sourceProperty.GetValue(source, null);
var targetValue = targetProperty.GetValue(target, null);
if (!Object.Equals(sourceValue, targetValue))
{
sourceProperty.SetValue(source, targetValue, null);
}
};
}
}
The following will return a property name as a string from a lambda expression:
public string PropertyName<TProperty>(Expression<Func<TProperty>> property)
{
var lambda = (LambdaExpression)property;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
return memberExpression.Member.Name;
}
Usage:
public class MyClass
{
public int World { get; set; }
}
...
var c = new MyClass();
Console.WriteLine("Hello {0}", PropertyName(() => c.World));
UPDATE
public static class Extensions
{
public static void Bind<TSourceProperty, TDestinationProperty>(this INotifyPropertyChanged source, Expression<Func<TSourceProperty, TDestinationProperty>> bindExpression)
{
var expressionDetails = GetExpressionDetails<TSourceProperty, TDestinationProperty>(bindExpression);
var sourcePropertyName = expressionDetails.Item1;
var destinationObject = expressionDetails.Item2;
var destinationPropertyName = expressionDetails.Item3;
// Do binding here
Console.WriteLine("{0} {1}", sourcePropertyName, destinationPropertyName);
}
private static Tuple<string, INotifyPropertyChanged, string> GetExpressionDetails<TSourceProperty, TDestinationProperty>(Expression<Func<TSourceProperty, TDestinationProperty>> bindExpression)
{
var lambda = (LambdaExpression)bindExpression;
ParameterExpression sourceExpression = lambda.Parameters.FirstOrDefault();
MemberExpression destinationExpression = (MemberExpression)lambda.Body;
var memberExpression = destinationExpression.Expression as MemberExpression;
var constantExpression = memberExpression.Expression as ConstantExpression;
var fieldInfo = memberExpression.Member as FieldInfo;
var destinationObject = fieldInfo.GetValue(constantExpression.Value) as INotifyPropertyChanged;
return new Tuple<string, INotifyPropertyChanged, string>(sourceExpression.Name, destinationObject, destinationExpression.Member.Name);
}
}
Usage:
public class TestSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Name { get; set; }
}
public class TestDestination : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var x = new TestSource();
var y = new TestDestination();
x.Bind<string, string>(Name => y.Id);
}
}
This question is very similar to: Retrieving Property name from lambda expression
(Cross-posting answer from https://stackoverflow.com/a/17220748/1037948)
I don't know if you need to bind to "subproperties", but inspecting the lambda.Body for Member.Name will only return the "final" property, not a "fully-qualified" property.
ex) o => o.Thing1.Thing2 would result in Thing2, not Thing1.Thing2.
This is problematic when trying to use this method to simplify EntityFramework DbSet.Include(string) with expression overloads.
So you can "cheat" and parse the Expression.ToString instead. Performance seemed comparable in my tests, so please correct me if this is a bad idea.
The Extension Method
/// <summary>
/// Given an expression, extract the listed property name; similar to reflection but with familiar LINQ+lambdas. Technique #via https://stackoverflow.com/a/16647343/1037948
/// </summary>
/// <remarks>Cheats and uses the tostring output -- Should consult performance differences</remarks>
/// <typeparam name="TModel">the model type to extract property names</typeparam>
/// <typeparam name="TValue">the value type of the expected property</typeparam>
/// <param name="propertySelector">expression that just selects a model property to be turned into a string</param>
/// <param name="delimiter">Expression toString delimiter to split from lambda param</param>
/// <param name="endTrim">Sometimes the Expression toString contains a method call, something like "Convert(x)", so we need to strip the closing part from the end</pa ram >
/// <returns>indicated property name</returns>
public static string GetPropertyName<TModel, TValue>(this Expression<Func<TModel, TValue>> propertySelector, char delimiter = '.', char endTrim = ')') {
var asString = propertySelector.ToString(); // gives you: "o => o.Whatever"
var firstDelim = asString.IndexOf(delimiter); // make sure there is a beginning property indicator; the "." in "o.Whatever" -- this may not be necessary?
return firstDelim < 0
? asString
: asString.Substring(firstDelim+1).TrimEnd(endTrim);
}//-- fn GetPropertyNameExtended
(Checking for the delimiter might even be overkill)
This is likely more than or not exactly what you asked for but I've done something similar to handle mapping of a property between two objects:
public interface IModelViewPropagationItem<M, V>
where M : BaseModel
where V : IView
{
void SyncToView(M model, V view);
void SyncToModel(M model, V view);
}
public class ModelViewPropagationItem<M, V, T> : IModelViewPropagationItem<M, V>
where M : BaseModel
where V : IView
{
private delegate void VoidDelegate();
public Func<M, T> ModelValueGetter { get; private set; }
public Action<M, T> ModelValueSetter { get; private set; }
public Func<V, T> ViewValueGetter { get; private set; }
public Action<V, T> ViewValueSetter { get; private set; }
public ModelViewPropagationItem(Func<M, T> modelValueGetter, Action<V, T> viewValueSetter)
: this(modelValueGetter, null, null, viewValueSetter)
{ }
public ModelViewPropagationItem(Action<M, T> modelValueSetter, Func<V, T> viewValueGetter)
: this(null, modelValueSetter, viewValueGetter, null)
{ }
public ModelViewPropagationItem(Func<M, T> modelValueGetter, Action<M, T> modelValueSetter, Func<V, T> viewValueGetter, Action<V, T> viewValueSetter)
{
this.ModelValueGetter = modelValueGetter;
this.ModelValueSetter = modelValueSetter;
this.ViewValueGetter = viewValueGetter;
this.ViewValueSetter = viewValueSetter;
}
public void SyncToView(M model, V view)
{
if (this.ViewValueSetter == null || this.ModelValueGetter == null)
throw new InvalidOperationException("Syncing to View is not supported for this instance.");
this.ViewValueSetter(view, this.ModelValueGetter(model));
}
public void SyncToModel(M model, V view)
{
if (this.ModelValueSetter == null || this.ViewValueGetter == null)
throw new InvalidOperationException("Syncing to Model is not supported for this instance.");
this.ModelValueSetter(model, this.ViewValueGetter(view));
}
}
This allows you to create an instance of this object and then use "SyncToModel" and "SyncToView" to move values back and forth. The following piece that goes with this allows you to group multiple of these things and move data back and forth with one call:
public class ModelViewPropagationGroup<M, V> : List<IModelViewPropagationItem<M, V>>
where M : BaseModel
where V : IView
{
public ModelViewPropagationGroup(params IModelViewPropagationItem<M, V>[] items)
{
this.AddRange(items);
}
public void SyncAllToView(M model, V view)
{
this.ForEach(o => o.SyncToView(model, view));
}
public void SyncAllToModel(M model, V view)
{
this.ForEach(o => o.SyncToModel(model, view));
}
}
Usage would look something like this:
private static readonly ModelViewPropagationItem<LoginModel, ILoginView, string> UsernamePI = new ModelViewPropagationItem<LoginModel, ILoginView, string>(m => m.Username.Value, (m, x) => m.Username.Value = x, v => v.Username, (v, x) => v.Username = x);
private static readonly ModelViewPropagationItem<LoginModel, ILoginView, string> PasswordPI = new ModelViewPropagationItem<LoginModel, ILoginView, string>(m => m.Password.Value, (m, x) => m.Password.Value = x, v => v.Password, (v, x) => v.Password = x);
private static readonly ModelViewPropagationGroup<LoginModel, ILoginView> GeneralPG = new ModelViewPropagationGroup<LoginModel, ILoginView>(UsernamePI, PasswordPI);
public UserPrincipal Login_Click()
{
GeneralPG.SyncAllToModel(this.Model, this.View);
return this.Model.DoLogin();
}
Hope this helps!
var pr = typeof(CCategory).GetProperties().Select(i => i.Name).ToList(); ;
declaration:
class Foo<T> {
public string Bar<T, TResult>(Expression<Func<T, TResult>> expersion)
{
var lambda = (LambdaExpression)expersion;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression)lambda.Body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
return memberExpression.Member.Name;
}
}
Usage:
var foo = new Foo<DummyType>();
var propName = foo.Bar(d=>d.DummyProperty)
Console.WriteLine(propName); //write "DummyProperty" string in shell

Categories