Implementing memoization in C# [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I know this topic (memoization) has been discussed quite a bit (like here), but no answer I could find satisfies the DRY principle as much as I would like, so please, read this whole question and the three points I want to address.
I have a simple support class like this:
public class Memoized<T1, TResult>
{
private readonly Func<T1, TResult> _f;
private readonly Dictionary<T1, TResult> _cache = new Dictionary<T1, TResult>();
public Memoized(Func<T1, TResult> f)
{
_f = f;
}
public TResult Invoke(T1 p1)
{
if (p1 == null) throw new ArgumentNullException(nameof(p1));
if (_cache.TryGetValue(p1, out var res)) return res;
return _cache[p1] = _f(p1);
}
public static Func<T1, TResult> Of(Func<T1, TResult> f)
{
var memo = new Memoized<T1, TResult>(f);
return x => memo.Invoke(x);
}
}
Nothing especially fancy, but it allows me to do this:
public class MyClass
{
public Func<int, bool> MemoizedMethod { get; }
private bool UncachedMethod(int v)
{
return v > 0;
}
public MyClass()
{
MemoizedMethod = Memoized<int, bool>.Of(UncachedMethod);
}
}
Now, even if the resulting code is not terribly noisy, I'm trying to figure out if the implementation could be more elegant, because currently I need:
an invokable property that acts as a Method.
a true method that should not be called directly.
a line in the constructor (cannot be an inline initialization) that links the two (with a third repetition of the function signature!).
Any suggestion for a strategy that allows to remove one (or two!) of the above points would be great.

In my struggle for elegance, I finally found what I think is the best syntax I saw anywhere:
private class MemoizedTest
{
private int _counter = 0;
public int Method(int p) => this.Memoized(p, x =>
{
return _counter += x;
});
}
Implementation (one pretty small extension class):
namespace System
{
public static class MemoizerExtension
{
internal static ConditionalWeakTable<object, ConcurrentDictionary<string, object>> _weakCache =
new ConditionalWeakTable<object, ConcurrentDictionary<string, object>>();
public static TResult Memoized<T1, TResult>(
this object context,
T1 arg,
Func<T1, TResult> f,
[CallerMemberName] string? cacheKey = null)
where T1 : notnull
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (cacheKey == null) throw new ArgumentNullException(nameof(cacheKey));
var objCache = _weakCache.GetOrCreateValue(context);
var methodCache = (ConcurrentDictionary<T1, TResult>) objCache
.GetOrAdd(cacheKey, _ => new ConcurrentDictionary<T1, TResult>());
return methodCache.GetOrAdd(arg, f);
}
}
}
Explanation
In the implementation I'm using a ConditionalWeakTable for caching, effectively extending the internal structure of the object invoking the memoization. As an additional key, the CallerMemberName is used, acting as a second key (this allows more memoizations for instance, and optionally more memoizations per method, if passing the cacheKey parameter explicitly).
The third key is the parameter of the invocation.
So, we have 3 runtime dictionary-like searches instead of 1, but a syntax that is a lot cleaner, IMO.
Is it worth it? I dunno, but my desire for elegance is satiated.
If someone else is interested, I'm including the tests for reference:
[TestFixture]
public class MemoizerTest
{
[Test]
public void MemoizationWorksOnFuncs()
{
int counter = 0;
Func<int, int> f = x => counter += x;
Assert.That(this.Memoized(1, f), Is.EqualTo(1));
Assert.That(this.Memoized(2, f), Is.EqualTo(3));
Assert.That(this.Memoized(2, f), Is.EqualTo(3));
Assert.That(this.Memoized(1, f), Is.EqualTo(1));
}
private class MemoizedTest
{
private int _counter = 0;
public int Method(int p)
=> this.Memoized(p, x => { return _counter += x; });
}
[Test]
public void MemoizationWorksOnInstances()
{
var obj1 = new MemoizedTest();
Assert.That(obj1.Method(5), Is.EqualTo(5));
Assert.That(obj1.Method(4), Is.EqualTo(9));
Assert.That(obj1.Method(5), Is.EqualTo(5));
Assert.That(obj1.Method(1), Is.EqualTo(10));
Assert.That(obj1.Method(4), Is.EqualTo(9));
obj1 = new MemoizedTest();
Assert.That(obj1.Method(5), Is.EqualTo(5));
Assert.That(obj1.Method(4), Is.EqualTo(9));
Assert.That(obj1.Method(5), Is.EqualTo(5));
Assert.That(obj1.Method(1), Is.EqualTo(10));
Assert.That(obj1.Method(4), Is.EqualTo(9));
}
[Test]
[Ignore("This test passes only when compiled in Release mode")]
public void WeakMemoizationCacheIsCleared()
{
var obj1 = new MemoizedTest();
var r1 = obj1.Method(5);
MemoizerExtension._weakCache.TryGetValue(obj1, out var cache);
var weakRefToCache = new WeakReference(cache);
cache = null;
GC.Collect(2);
obj1 = null;
GC.Collect();
GC.Collect();
var msg = weakRefToCache.TrackResurrection;
Assert.That(weakRefToCache.IsAlive, Is.False, "The weak reference should be dead.");
Assert.That(r1, Is.EqualTo(5));
}
}

If you capture the dictionary in the lambda, your state will be maintained implicitly.
public class Memoized
{
// Example with a single parameter. That parameter becomes the key to the dictionary.
public static Func<T1, TRet> Of<T1, TRet>(Func<T1, TRet> f)
{
ConcurrentDictionary<T1, TRet> cache = new ConcurrentDictionary<T1, TRet>();
return (arg1) => cache.GetOrAdd(arg1, xarg=>f(xarg));
}
// Example with two parameters. The key is a tuple, and it must be unpacked before calling func.
// Three or more parameters generalize from this
public static Func<T1, T2, TRet> Of<T1, T2, TRet>(Func<T1, T2, TRet> f)
{
ConcurrentDictionary<Tuple<T1,T2>, TRet> cache = new ConcurrentDictionary<Tuple<T1, T2>, TRet>();
return (arg1, arg2) => cache.GetOrAdd(new Tuple<T1,T2>(arg1, arg2),
(xarg)=>f(xarg.Item1, xarg.Item2)
);
}
}
Usage example:
class Test
{
public int Method(String s, String s2)
{
return 99;
}
}
class Program
{
static bool UncachedMethod(int x) { return x > 0; }
static void Main(string[] args)
{
var cached = Memoized.Of<int,bool>(UncachedMethod);
var exampleCall = cached(44);
var exampleCall2 = cached(44);
// Capture a non-static member function
var x = new Test();
var cachedX = Memoized.Of<String, String,int>(x.Method);
var exampleCall3 = cachedX("a","b");
}
}

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.

Transform an object to another, LINQ-style

LINQ allows to elegantly transform the collection returned by a method to a different collection, i.e.
var x = SomeMethod().Select(t => new { ... });
Now, is there a concise way in C# to transform the return value of a method without introducing an intermediary variable? Declaring and invoking a lambda seems to work but is quite ugly:
var x = new Func<T, object>(t => { return new { ... }; })(SomeMethod());
Am I missing something obvious or is this the best one can do with C# today?
You can apply Select followed by Single to sequence of one item created from the result of calling SomeMethod, as follows:
var x = Enumerable.Repeat(SomeMethod(), 1).Select(r => new {...}).Single();
If you do it a lot, you can make a generic extension method for this:
static class MyExtensions {
public static TRes Transform<TSrc,TRes>(this TSrc src, Func<TSrc,TRes> selector) {
return selector(src);
}
}
Now the syntax becomes very simple:
var res = SomeMethod().Transform(x => new { ... });
I just figured that a generic extension method could fill the gap:
public static class TransformExtension
{
public static T2 Transform<T1, T2>(this T1 t1, Func<T1, T2> transform)
{
return transform(t1);
}
}
Sample usage:
public class A { };
public class B { };
void Foo()
{
var a = new A();
var b = a.Transform(x => new B());
}
Happy to hear why that's possibly a terrible idea.

Increment value from expression

I want to write a closure and increment it's value but i'm not able to do it. Here is my code
int i = 0;
Expression<Func<bool>> closurExpression = () =>
{
i++;
return i != 0;
};
but i get multuple errors about A lambda expression with a statement body cannot be converted to an expression tree or An expression tree may not contain an assignment operator etc. Is it possible without using external tools as Mono.Cecil etc?
for the question: why am I asking for it. I want to write a simple wrapper (for a signature Func<T,T> at least that will calculate count of calls. For example:
Wrapper<int> wrapper = () => 5;
for(int i = 0; i < 10; i++)
wrapper();
int calls = wrapper.Calls; // 10;
my first realisation was:
class FunctionWithCounter<T, TResult>
{
private readonly Func<T, TResult> function;
public int Calls { get; set; }
private FunctionWithCounter(Func<T, TResult> function)
{
Calls = 0;
this.function = function;
}
public static implicit operator FunctionWithCounter<T, TResult>(Func<T, TResult> func)
{
return new FunctionWithCounter<T, TResult>(func);
}
public TResult this[T arg]
{
get
{
Calls++;
return function(arg);
}
}
}
but after i get that recurcive functions won't work properly. For example for this code
int fact(int n) { return n < 2 ? 1 : n * fact(n - 1); }
Calls count will be 1 for any n. So idea is: get source function, and inject increment of Calls for every call of method increment it. All inner calls of method somefunc should be replaced by our method funcWithInjection, in this case we'll catch recursive functions too. Here is my code, but it doesn't work (except inject, so this code really increments a field value, but I cannot add source's method body to the tail and compile it, you can play with it if you will):
public class FunctionWithCounter<T, TResult> where T : new()
{
private readonly Func<T, TResult> _functionWithInjection;
private int _calls;
public int Calls
{
get
{
return _calls;
}
}
public FunctionWithCounter(Func<T, TResult> function)
{
_calls = 0;
var targetObject = function.Target ?? new object();
var dynMethod = new DynamicMethod(new Guid().ToString(), typeof(TResult), new[] { targetObject.GetType(), typeof(T), typeof(FunctionWithCounter<T, TResult>) }, true);
var ilGenerator = GenerateInjection(dynMethod);
ilGenerator.Emit(OpCodes.Ret);
var resDelegate = dynMethod.CreateDelegate(typeof(Func<T, FunctionWithCounter<T, TResult>, TResult>), targetObject);
var functionWithInjection = (Func<T, FunctionWithCounter<T, TResult>, TResult>)resDelegate;
var targetMethodBody = function.Method.GetMethodBody();
Debug.Assert(targetMethodBody != null, "mbody != null");
//here i need to write method body in the tail of dynamic method.
_functionWithInjection = function;
_functionWithInjection = t =>
{
functionWithInjection(t, this);
return default(TResult);
};
//finally here should be _functionWithInjection = t => functionWithInjection(t, this);
}
private ILGenerator GenerateInjection(DynamicMethod method)
{
var callsFieldInfo = GetType().GetField("_calls", BindingFlags.NonPublic | BindingFlags.Instance);
Debug.Assert(callsFieldInfo != null, "callsFieldInfo != null");
var ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
ilGenerator.Emit(OpCodes.Ldarg_2);
ilGenerator.Emit(OpCodes.Dup);
ilGenerator.Emit(OpCodes.Ldfld, callsFieldInfo);
ilGenerator.Emit(OpCodes.Ldc_I4_1);
ilGenerator.Emit(OpCodes.Add);
ilGenerator.Emit(OpCodes.Stfld, callsFieldInfo);
return ilGenerator;
}
public static implicit operator FunctionWithCounter<T, TResult>(Func<T, TResult> func)
{
return new FunctionWithCounter<T, TResult>(func);
}
public TResult this[T arg]
{
get
{
return _functionWithInjection(arg);
}
}
}
My second realisation was based on Emit API, but it's too complex and It was unfinished for a long time...
So now this is my 3rd try and i want to use expressions. Шt should look something like this:
public FunctionWithCounter(Expression<Func<T, TResult>> function)
{
Action action = () => _calls++;
Expression<Action> closurExpression = () => action();
var result = Expression.Block(closurExpression, function);
_functionWithInjection = Expression.Lambda<Func<T,TResult>>(result).Compile();
}
sorry for my english, but i really want to realize this idea
Well, you can do sidestep the rules using Interlocked.Increment:
int i = 0;
Expression<Func<bool>> expression = () => Interlocked.Increment(ref i) != 0;
... but I would be very cautious about doing so. I wouldn't expect many pieces of code which deal with expression trees to handle this terribly cleanly, given the side-effect involved.
The above does seem to work, in terms of behaving how I'd expect it to:
int i = -2;
Expression<Func<bool>> expression = () => Interlocked.Increment(ref i) != 0;
var del = expression.Compile();
Console.WriteLine(del()); // True
Console.WriteLine(del()); // False
Console.WriteLine(del()); // True
Console.WriteLine(del()); // True
Console.WriteLine(i); // 2
I think that your first approach was cleaner and ok for simple, non-recursive cases.
If you allow your wrapped functions to be aware of recursion, you can take it a little further and make the wrapper an argument to the function itself:
class RecursiveFunctionWithCounter<T, TResult>
{
private readonly Func<T, RecursiveFunctionWithCounter<T, TResult>, TResult> function;
public int Calls { get; set; }
public RecursiveFunctionWithCounter(Func<T, RecursiveFunctionWithCounter<T, TResult>, TResult> function)
{
Calls = 0;
this.function = function;
}
public TResult this[T arg]
{
get
{
Calls++;
return function(arg, this);
}
}
}
And use it like this:
var rw = new RecursiveFunctionWithCounter<int, int>(
(n, self) => { return n < 2 ? 1 : n * self[n - 1]; }
);
int rr = rw[3]; // rr=6
int rc = rw.Calls; // rc=3
On the other hand, if what you really want to do is instrument some existing methods in your code, consider doing a little Aspect Oriented Programming (with PostSharp for instance, this is an example of an aspect that increments a performance counter on each method call). This way you could just add an attribute like IncrementPerformanceCounterAttribute to your methods and the AOT library will do the rest.

Make a function with Calls counter

Question is simple: how to make it as simple as possible for calling code? My code is a bit stupid, but i see no way.
using System;
namespace ConsoleApplication48
{
class FunctionWithCounter<T, TResult>
{
private readonly Func<T, TResult> function;
public int Calls { get; private set; }
private FunctionWithCounter(Func<T, TResult> function)
{
Calls = 0;
this.function = function;
}
public static implicit operator FunctionWithCounter<T, TResult>(Func<T, TResult> func)
{
return new FunctionWithCounter<T, TResult>(func);
}
public TResult this[T arg]
{
get
{
Calls++;
return function(arg);
}
}
}
class Program
{
static void Main()
{
FunctionWithCounter<double, double> func = (Func<double, double>)(x => x*x);
for (int i = 0; i < 5; i++)
{
double d = func[i];
}
Console.WriteLine(func.Calls);
Console.ReadKey();
}
}
}
So i use indexer to call like this func[x] instead of func(x), and there's some difficultes (can't call like a void-method). But it's most simple i think. Any offers?
for the price of 1 extra line, I'd restore it back to at least normal function syntax. Also get rid of the implicit constructor, it doesn't really save you anything, and without it, the syntax look simpler.
class FunctionWithCounter<T, TResult>
{
public readonly Func<T, TResult> Function;
public int Calls { get; private set; }
public FunctionWithCounter(Func<T, TResult> function)
{
Calls = 0;
Function = x =>
{
Calls++;
return function(x);
};
}
}
internal class Program
{
private static void Main(string[] args)
{
var callCounter = new FunctionWithCounter<double,double>(x => x * x);
var func = callCounter.Function;
for (int i = 0; i < 5; i++)
{
double d = func(i);
}
Console.WriteLine(callCounter.Calls);
Console.ReadKey();
}
}

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

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.

Categories