1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using Microsoft.CSharp.RuntimeBinder;
- namespace ClaySharp.Behaviors {
- public class ClayFactoryBehavior : ClayBehavior {
- public override object InvokeMember(Func<object> proceed, object self, string name, INamedEnumerable<object> args) {
- dynamic shape = new Clay(
- new InterfaceProxyBehavior(),
- new PropBehavior(),
- new ArrayPropAssignmentBehavior(),
- new NilResultBehavior());
- shape.ShapeName = name;
- if (args.Positional.Count() == 1) {
- var options = args.Positional.Single();
- var assigner = GetAssigner(options.GetType());
- assigner.Invoke(shape, options);
- }
- foreach (var kv in args.Named) {
- shape[kv.Key] = kv.Value;
- }
- return shape;
- }
- private static Action<dynamic, object> GetAssigner(Type sourceType) {
- lock (_assignerCache) {
- Action<dynamic, object> assigner;
- if (_assignerCache.TryGetValue(sourceType, out assigner))
- return assigner;
-
-
-
-
-
-
- var targetParameter = Expression.Parameter(typeof(object), "target");
- var sourceParameter = Expression.Parameter(typeof(object), "source");
-
-
- var assignments = sourceType.GetProperties().Select(
- property => Expression.Dynamic(
- Binder.SetMember(
- CSharpBinderFlags.None,
- property.Name,
- typeof(void),
- new[] {
- CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
- CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
- }),
- typeof(void),
- targetParameter,
- Expression.Property(
- Expression.Convert(sourceParameter, sourceType),
- property)));
- var lambda = Expression.Lambda<Action<dynamic, object>>(
- Expression.Block(assignments),
- targetParameter,
- sourceParameter);
- assigner = lambda.Compile();
- _assignerCache.Add(sourceType, assigner);
- return assigner;
- }
- }
- static readonly Dictionary<Type, Action<dynamic, object>> _assignerCache = new Dictionary<Type, Action<dynamic, object>>();
- }
- }
|