Ich habe einen Typ in MiscUtil
aufgerufen, PropertyCopy
der etwas Ähnliches tut - obwohl er eine neue Instanz des Zieltyps erstellt und die Eigenschaften in diesen kopiert.
Die Typen müssen nicht identisch sein - es werden lediglich alle lesbaren Eigenschaften vom Typ "Quelle" in den Typ "Ziel" kopiert. Wenn die Typen gleich sind, funktioniert das natürlich eher :) Es ist übrigens eine flache Kopie.
Im Codeblock am Ende dieser Antwort habe ich die Funktionen der Klasse erweitert. Zum Kopieren von einer Instanz in eine andere PropertyInfo
werden zur Ausführungszeit einfache Werte verwendet. Dies ist langsamer als die Verwendung eines Ausdrucksbaums. Die Alternative wäre jedoch, eine dynamische Methode zu schreiben, auf die ich nicht allzu scharf bin. Wenn die Leistung für Sie absolut kritisch ist, lassen Sie es mich wissen und ich werde sehen, was ich tun kann. Um die Methode zu verwenden, schreiben Sie etwas wie:
MyType instance1 = new MyType();
MyType instance2 = new MyType();
PropertyCopy.Copy(instance1, instance2);
(Wo Copy
ist eine generische Methode, die mit Typinferenz aufgerufen wird).
Ich bin nicht wirklich bereit, eine vollständige MiscUtil-Version zu erstellen, aber hier ist der aktualisierte Code, einschließlich der Kommentare. Ich werde sie nicht für den SO-Editor neu verpacken - kopiere einfach den ganzen Teil.
(Ich würde wahrscheinlich auch die API in Bezug auf die Benennung ein wenig neu gestalten, wenn ich von vorne anfangen würde, aber ich möchte bestehende Benutzer nicht brechen ...)
#if DOTNET35
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace MiscUtil.Reflection
{
public static class PropertyCopy
{
public static void Copy<TSource, TTarget>(TSource source, TTarget target)
where TSource : class
where TTarget : class
{
PropertyCopier<TSource, TTarget>.Copy(source, target);
}
}
public static class PropertyCopy<TTarget> where TTarget : class, new()
{
public static TTarget CopyFrom<TSource>(TSource source) where TSource : class
{
return PropertyCopier<TSource, TTarget>.Copy(source);
}
}
internal static class PropertyCopier<TSource, TTarget>
{
private static readonly Func<TSource, TTarget> creator;
private static readonly List<PropertyInfo> sourceProperties = new List<PropertyInfo>();
private static readonly List<PropertyInfo> targetProperties = new List<PropertyInfo>();
private static readonly Exception initializationException;
internal static TTarget Copy(TSource source)
{
if (initializationException != null)
{
throw initializationException;
}
if (source == null)
{
throw new ArgumentNullException("source");
}
return creator(source);
}
internal static void Copy(TSource source, TTarget target)
{
if (initializationException != null)
{
throw initializationException;
}
if (source == null)
{
throw new ArgumentNullException("source");
}
for (int i = 0; i < sourceProperties.Count; i++)
{
targetProperties[i].SetValue(target, sourceProperties[i].GetValue(source, null), null);
}
}
static PropertyCopier()
{
try
{
creator = BuildCreator();
initializationException = null;
}
catch (Exception e)
{
creator = null;
initializationException = e;
}
}
private static Func<TSource, TTarget> BuildCreator()
{
ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
var bindings = new List<MemberBinding>();
foreach (PropertyInfo sourceProperty in typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
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.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
{
throw new ArgumentException("Property " + sourceProperty.Name + " is static 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)));
sourceProperties.Add(sourceProperty);
targetProperties.Add(targetProperty);
}
Expression initializer = Expression.MemberInit(Expression.New(typeof(TTarget)), bindings);
return Expression.Lambda<Func<TSource, TTarget>>(initializer, sourceParameter).Compile();
}
}
}
#endif