那麼,我有一個真的很可怕你可以做到這一點。
您可以編寫一個方法,它使用反射(與我同在!)來計算特定類型的所有屬性,並構建一個委託(使用Reflection.Emit)將屬性從該類型複製到另一個類型。然後使用匿名類型來確保您只需構建一次複製委託,因此速度很快。那麼你的方法應該是這樣的:
public static Expression<Func<Foo, FooEditDto>> EditDtoSelector()
{
return f => MagicCopier<FooEditDto>.Copy(new {
f.PropertyA, f.PropertyB, f.PropertyC, f.PropertyD, f.PropertyC
});
}
這裏的細微差別:
- MagicCopier是一個通用型和複製是一種通用的方法,這樣可以明確指定「目標」類型,但含蓄指定「源」類型。
- 它使用投影初始推斷從使用的表達式屬性的名稱來初始化匿名類型
我不知道它是否真的值得,但它是一個相當有趣的想法...我可能不得不實施它:)
編輯:與MemberInitExpression我們可以用表達式樹做這一切,這使得它比CodeDOM更容易。今晚會試一試...
編輯:完成,它實際上很簡單的代碼。下面是類:
/// <summary>
/// Generic class which copies to its target type from a source
/// type specified in the Copy method. The types are specified
/// separately to take advantage of type inference on generic
/// method arguments.
/// </summary>
public static class PropertyCopy<TTarget> where TTarget : class, new()
{
/// <summary>
/// Copies all readable properties from the source to a new instance
/// of TTarget.
/// </summary>
public static TTarget CopyFrom<TSource>(TSource source) where TSource : class
{
return PropertyCopier<TSource>.Copy(source);
}
/// <summary>
/// Static class to efficiently store the compiled delegate which can
/// do the copying. We need a bit of work to ensure that exceptions are
/// appropriately propagated, as the exception is generated at type initialization
/// time, but we wish it to be thrown as an ArgumentException.
/// </summary>
private static class PropertyCopier<TSource> where TSource : class
{
private static readonly Func<TSource, TTarget> copier;
private static readonly Exception initializationException;
internal static TTarget Copy(TSource source)
{
if (initializationException != null)
{
throw initializationException;
}
if (source == null)
{
throw new ArgumentNullException("source");
}
return copier(source);
}
static PropertyCopier()
{
try
{
copier = BuildCopier();
initializationException = null;
}
catch (Exception e)
{
copier = null;
initializationException = e;
}
}
private static Func<TSource, TTarget> BuildCopier()
{
ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
var bindings = new List<MemberBinding>();
foreach (PropertyInfo sourceProperty in typeof(TSource).GetProperties())
{
if (!sourceProperty.CanRead)
{
continue;
}
PropertyInfo targetProperty = typeof(TTarget).GetProperty(sourceProperty.Name);
if (targetProperty == null)
{
throw new ArgumentException("Property " + sourceProperty.Name
+ " is not present and accessible in " + typeof(TTarget).FullName);
}
if (!targetProperty.CanWrite)
{
throw new ArgumentException("Property " + sourceProperty.Name
+ " is not writable in " + typeof(TTarget).FullName);
}
if (!targetProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
{
throw new ArgumentException("Property " + sourceProperty.Name
+ " has an incompatible type in " + typeof(TTarget).FullName);
}
bindings.Add(Expression.Bind(targetProperty, Expression.Property(sourceParameter, sourceProperty)));
}
Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
return Expression.Lambda<Func<TSource,TTarget>>(initializer, sourceParameter).Compile();
}
}
,把它:
TargetType target = PropertyCopy<TargetType>.CopyFrom(new { First="Foo", Second="Bar" });
請參閱我添加的說明。 FooEditDto是FooDto的一個子類。 – 2008-10-21 19:29:47