Skip to content

Instantly share code, notes, and snippets.

@ldhertert
Created April 12, 2011 18:51
Show Gist options
  • Save ldhertert/916128 to your computer and use it in GitHub Desktop.
Save ldhertert/916128 to your computer and use it in GitHub Desktop.
This is ugly. Never meant for anyone else to see
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Core.Extensibility.Extensions;
using System.ComponentModel;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
namespace Core.Reflection
{
public interface IMappableObject<T>
{
object GetValue(T srcObject);
void SetValue(T srcObject, object value);
}
public class PropertySpecifier<T> : IMappableObject<T>
{
public PropertySpecifier(Expression<Func<T, object>> expression)
{
MemberExpression _expression = null;
if (expression.Body is MemberExpression)
_expression = (expression.Body) as MemberExpression;
else if (expression.Body is UnaryExpression)
_expression = ((UnaryExpression)expression.Body).Operand as MemberExpression;
if (_expression == null)
throw new ArgumentException();
this.PropertyName = _expression.Member.Name;
}
public PropertySpecifier(string propertyName)
{
this.PropertyName = propertyName;
}
public string PropertyName { get; set; }
public object GetValue(T srcObject)
{
return srcObject.GetMemberValue(this.PropertyName);
}
public void SetValue(T srcObject, object value)
{
srcObject.SetMemberValue(this.PropertyName, value, false);
}
}
public class ValueSpecifier<T> : IMappableObject<T>
{
private object Value { get; set; }
public ValueSpecifier(object value)
{
this.Value = value;
}
public object GetValue(T srcObject)
{
return this.Value;
}
public void SetValue(T srcObject, object value)
{
throw new InvalidOperationException();
}
}
public class MethodSpecifier<T> : IMappableObject<T>
{
Func<T, object> _expression;
public MethodSpecifier(Func<T, object> expression)
{
_expression = expression;
if (_expression == null)
throw new ArgumentException();
}
public object GetValue(T srcObject)
{
return _expression(srcObject);
}
public void SetValue(T srcObject, object value)
{
throw new InvalidOperationException();
}
}
public class PropertyMapEntry<TLeft, TRight>
{
public IMappableObject<TLeft> Left { get; set; }
public IMappableObject<TRight> Right { get; set; }
public Func<TLeft, bool> Condition { get; set; }
[Obsolete("Use 'To' instead")]
public PropertyMapEntry<TLeft, TRight> MapsTo(Expression<Func<TRight, object>> expression)
{
this.Right = new PropertySpecifier<TRight>(expression);
return this;
}
[Obsolete("Use 'To' instead")]
public PropertyMapEntry<TLeft, TRight> MapsTo(string propertyName)
{
this.Right = new PropertySpecifier<TRight>(propertyName);
return this;
}
public PropertyMapEntry<TLeft, TRight> To(Expression<Func<TRight, object>> expression)
{
this.Right = new PropertySpecifier<TRight>(expression);
return this;
}
public PropertyMapEntry<TLeft, TRight> To(string propertyName)
{
this.Right = new PropertySpecifier<TRight>(propertyName);
return this;
}
public PropertyMapEntry<TLeft, TRight> Conditionally(Func<TLeft, bool> condition)
{
this.Condition = condition;
return this;
}
public void MapValue(TLeft leftObject, TRight rightObejct)
{
if (this.Condition == null || this.Condition(leftObject))
{
this.Right.SetValue(rightObejct, this.Left.GetValue(leftObject));
}
}
public void MapValueIfReadOnly(TLeft leftObject, TRight rightObject)
{
//checks the rightObject type and any metadata type associated with it for ReadOnly attribute on the Property.
//if found, it will set the value.
Type t = typeof(TRight);
PropertyInfo pi = t.GetProperty(((PropertySpecifier<TRight>)this.Right).PropertyName);
bool isReadOnly = ReadOnlyAttribute.IsDefined(pi, typeof(ReadOnlyAttribute));
if (!isReadOnly)
{
//check for meta data class.
MetadataTypeAttribute[] metaAttr = (MetadataTypeAttribute[])t.GetCustomAttributes(typeof(MetadataTypeAttribute), true);
if (metaAttr.Length > 0)
{
foreach (MetadataTypeAttribute attr in metaAttr)
{
t = attr.MetadataClassType;
pi = t.GetProperty(((PropertySpecifier<TRight>)this.Right).PropertyName);
if (pi != null)
isReadOnly = ReadOnlyAttribute.IsDefined(pi, typeof(ReadOnlyAttribute));
if (isReadOnly)
break;
}
}
}
if ((this.Condition == null || this.Condition(leftObject)) && isReadOnly)
{
this.Right.SetValue(rightObject, this.Left.GetValue(leftObject));
}
}
}
public class PropertyMapper<TLeft, TRight>
{
public PropertyMapper()
{
Entries = new List<PropertyMapEntry<TLeft, TRight>>();
}
public PropertyMapEntry<TLeft, TRight> Map(Func<TLeft, object> expression)
{
PropertyMapEntry<TLeft, TRight> mapEntry = new PropertyMapEntry<TLeft, TRight> { Left = new MethodSpecifier<TLeft>(expression), Right = null };
this.Entries.Add(mapEntry);
return mapEntry;
}
public PropertyMapEntry<TLeft, TRight> Map(string propertyName)
{
PropertyMapEntry<TLeft, TRight> mapEntry = new PropertyMapEntry<TLeft, TRight> { Left = new PropertySpecifier<TLeft>(propertyName), Right = null };
this.Entries.Add(mapEntry);
return mapEntry;
}
public PropertyMapEntry<TLeft, TRight> MapConstant(object value)
{
PropertyMapEntry<TLeft, TRight> mapEntry = new PropertyMapEntry<TLeft, TRight> { Left = new ValueSpecifier<TLeft>(value), Right = null };
this.Entries.Add(mapEntry);
return mapEntry;
}
public List<PropertyMapEntry<TLeft, TRight>> Entries { get; set; }
}
public class BidirectionalPropertyMapper<TLeft, TRight>
{
public class UnmappedBiderectionalProperties
{
public PropertyMapEntry<TLeft, TRight> UnmappedLeftToRight { get; set; }
public PropertyMapEntry<TRight, TLeft> UnmappedRightToLeft { get; set; }
public UnmappedBiderectionalProperties MapsTo(Expression<Func<TRight, object>> expression)
{
this.UnmappedLeftToRight.Right = new PropertySpecifier<TRight>(expression);
this.UnmappedRightToLeft.Left = new PropertySpecifier<TRight>(expression);
return this;
}
public UnmappedBiderectionalProperties MapsTo(string propertyName)
{
this.UnmappedLeftToRight.Right = new PropertySpecifier<TRight>(propertyName);
this.UnmappedRightToLeft.Left = new PropertySpecifier<TRight>(propertyName);
return this;
}
public UnmappedBiderectionalProperties ConditionallyLeftToRight(Func<TLeft, bool> condition)
{
this.UnmappedLeftToRight.Condition = condition;
return this;
}
public UnmappedBiderectionalProperties ConditionallyRightToLeft(Func<TRight, bool> condition)
{
this.UnmappedRightToLeft.Condition = condition;
return this;
}
}
public BidirectionalPropertyMapper()
{
this.LeftToRightMapper = new PropertyMapper<TLeft, TRight>();
this.RightToLeftMapper = new PropertyMapper<TRight, TLeft>();
}
public PropertyMapper<TLeft, TRight> LeftToRightMapper { get; set; }
public PropertyMapper<TRight, TLeft> RightToLeftMapper { get; set; }
public UnmappedBiderectionalProperties OneToOneProperty(Expression<Func<TLeft, object>> leftExpression)
{
UnmappedBiderectionalProperties unmappedProperties = new UnmappedBiderectionalProperties();
unmappedProperties.UnmappedLeftToRight = new PropertyMapEntry<TLeft, TRight> { Left = new PropertySpecifier<TLeft>(leftExpression), Right = null };
unmappedProperties.UnmappedRightToLeft = new PropertyMapEntry<TRight, TLeft> { Left = null, Right = new PropertySpecifier<TLeft>(leftExpression) };
this.LeftToRightMapper.Entries.Add(unmappedProperties.UnmappedLeftToRight);
this.RightToLeftMapper.Entries.Add(unmappedProperties.UnmappedRightToLeft);
return unmappedProperties;
}
public UnmappedBiderectionalProperties OneToOneProperty(string propertyName)
{
UnmappedBiderectionalProperties unmappedProperties = new UnmappedBiderectionalProperties();
unmappedProperties.UnmappedLeftToRight = new PropertyMapEntry<TLeft, TRight> { Left = new PropertySpecifier<TLeft>(propertyName), Right = null };
unmappedProperties.UnmappedRightToLeft = new PropertyMapEntry<TRight, TLeft> { Left = null, Right = new PropertySpecifier<TLeft>(propertyName) };
this.LeftToRightMapper.Entries.Add(unmappedProperties.UnmappedLeftToRight);
this.RightToLeftMapper.Entries.Add(unmappedProperties.UnmappedRightToLeft);
return unmappedProperties;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment