Last active
August 29, 2015 14:20
-
-
Save kobi/6423eaa13cca238447a8 to your computer and use it in GitHub Desktop.
Example output for Stack Overflow question: How to simplify repeating if-then-assign construction? - http://stackoverflow.com/a/29918452/7586
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#@ template debug="false" hostspecific="false" language="C#" #> | |
<#@ assembly name="System.Core" #> | |
<#@ assembly name="$(TargetPath)" #> | |
<#@ import namespace="System.Collections.Generic" #> | |
<#@ import namespace="System.Linq.Expressions" #> | |
<#@ import namespace="ConsoleApplicationT4So29913514" #> | |
<#@ output extension=".generated.cs" #> | |
<# | |
// Consider including the namespace in the class names. | |
// You only need to change the mappings. | |
//var product = new Mapper("Product", "ProductEntity") { "Name", {"Id", "ServiceId"} }; | |
//var person = new Mapper("Person", "DbPerson") { "Employee", {"Name", "FullName"}, {"Addredd", "HomeAddress"} }; | |
//var product = new Mapper<Student,StudentRecord>{{}}; | |
var mappings = new Mapper[] { | |
new Mapper<Student,StudentRecord> | |
{ | |
{s=>s.Title, t=>t.EntityTitle}, | |
{s=>s.StudentId, t=>t.Id}, | |
s=>s.Name, | |
s=>s.LuckyNumber, | |
}, | |
new Mapper<Car,RaceCar> | |
{ | |
c=>c.Color, | |
c=>c.Driver, | |
{c=>c.Driver.Length, r=>r.DriverNameDisplayWidth}, | |
}, | |
}; | |
#> | |
// !!! | |
// !!! Do not modify this file, it is automatically generated. Change the .tt file instead. !!! | |
// !!! | |
namespace Your.Mapper | |
{ | |
partial class Mapper | |
{ | |
<# foreach(var mapping in mappings) { | |
#>/// <summary> | |
/// Set <paramref name="target"/> properties by copying them from <paramref name="source"/>. | |
/// </summary> | |
/// <remarks>Mapping:<br/> | |
<#foreach(var property in mapping){ | |
#>/// <see cref="<#=mapping.SourceType#>.<#=property.SourceProperty#>"/> → <see cref="<#=mapping.TargetType#>.<#=property.TargetProperty#>"/> <br/> | |
<#} | |
#>/// </remarks> | |
/// <returns><c>true</c> if any property was changed, <c>false</c> if all properties were the same.</returns> | |
public bool ModifyExistingEntity(<#=mapping.SourceType#> source, <#=mapping.TargetType#> target) | |
{ | |
bool dirty = false; | |
<# foreach(var property in mapping) { | |
#>if (target.<#=property.TargetProperty#> != source.<#=property.SourceProperty#>) | |
{ | |
dirty = true; | |
target.<#=property.TargetProperty#> = source.<#=property.SourceProperty#>; | |
} | |
<#} | |
#>return dirty; | |
} | |
<# | |
} | |
#> | |
} | |
} | |
<#+ | |
class Mapper : IEnumerable<PropertyMapper> | |
{ | |
private readonly List<PropertyMapper> _properties; | |
public Mapper(string sourceType, string targetType) | |
{ | |
SourceType = sourceType; | |
TargetType = targetType; | |
_properties = new List<PropertyMapper>(); | |
} | |
public string SourceType { get; set; } | |
public string TargetType { get; set; } | |
public void Add(string fieldName) | |
{ | |
_properties.Add(new PropertyMapper {SourceProperty = fieldName, TargetProperty = fieldName}); | |
} | |
public void Add(string sourceProperty, string targetProperty) | |
{ | |
_properties.Add(new PropertyMapper { SourceProperty = sourceProperty, TargetProperty = targetProperty }); | |
} | |
IEnumerator<PropertyMapper> IEnumerable<PropertyMapper>.GetEnumerator() { return _properties.GetEnumerator(); } | |
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _properties.GetEnumerator(); } | |
} | |
class PropertyMapper | |
{ | |
public string SourceProperty { get; set; } | |
public string TargetProperty { get; set; } | |
} | |
class Mapper<TSource, TTarget> : Mapper | |
{ | |
public Mapper() | |
: base(typeof(TSource).FullName, typeof(TTarget).FullName) | |
{ | |
} | |
private static string GetExpressionMemberAccess(LambdaExpression getProperty) | |
{ | |
var member = (MemberExpression)getProperty.Body; | |
//var lambdaParameterName = (ParameterExpression)member.Expression; | |
var lambdaParameterName = getProperty.Parameters[0]; // `x` in `x => x.PropertyName` | |
var labmdaBody = member.ToString(); | |
//will not work with indexer. | |
return labmdaBody.Substring(lambdaParameterName.Name.Length + 1); //+1 to remove the `.`, get "PropertyName" | |
} | |
public void Add<TProperty>(Expression<Func<TSource, TProperty>> getSourceProperty, Expression<Func<TTarget, TProperty>> getTargetProperty) | |
{ | |
Add(GetExpressionMemberAccess(getSourceProperty), GetExpressionMemberAccess(getTargetProperty)); | |
} | |
/// <summary> | |
/// The doesn't really make sense, but we assume we have <c>source=>source.Property</c>, <c>target=>target.Property</c> | |
/// </summary> | |
public void Add<TProperty>(Expression<Func<TSource, TProperty>> getProperty) | |
{ | |
Add(GetExpressionMemberAccess(getProperty)); | |
} | |
} | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment