Автоматически применять значения свойств одного объекта к другому того же типа?
У меня есть тип в MiscUtil
под названием .cs-file PropertyCopy
, который делает нечто подобное, хотя c#-language создает новый экземпляр целевого linq-to-sql типа и копирует в него свойства.
Он c-sharp не требует, чтобы типы были linq-to-sql одинаковыми - он просто копирует c# все читаемые свойства из c#.net «исходного» типа в «целевой» тип. Конечно, если linq-to-sql типы совпадают, это с большей linq2sql вероятностью сработает :) Кстати, это linq2sql мелкая копия.
В блоке кода sql-to-linq внизу этого ответа я расширил c# возможности класса. Для копирования c# из одного экземпляра в другой c-sharp он использует простые значения csharp PropertyInfo
во время выполнения - это c#.net медленнее, чем использование visual-c# дерева выражений, но альтернативой c#.net было бы написать динамический .cs-file метод, который мне не очень visual-c# нравится. Если производительность csharp для вас абсолютно критична, дайте visual-c# мне знать, и я посмотрю, что linq-to-sql я могу сделать. Чтобы использовать c# метод, напишите что-нибудь c#.net вроде:
MyType instance1 = new MyType();
// Do stuff
MyType instance2 = new MyType();
// Do stuff
PropertyCopy.Copy(instance1, instance2);
(где Copy
- общий метод, вызываемый csharp с использованием вывода типа).
Я .cs-file не совсем готов к выпуску c#.net полной версии MiscUtil, но linq2sql вот обновленный код, включая c# комментарии. Я не собираюсь visual-c# перематывать их для редактора c-sharp SO - просто скопируйте весь linq-to-sql кусок.
(Я бы также, вероятно, немного c#-language изменил дизайн API с точки c#-language зрения именования, если бы c#.net я начинал с нуля, но я не linq-to-sql хочу нарушать работу существующих c#.net пользователей ...)
#if DOTNET35
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace MiscUtil.Reflection
{
///
/// Non-generic class allowing properties to be copied from one instance
/// to another existing instance of a potentially different type.
///
public static class PropertyCopy
{
///
/// Copies all public, readable properties from the source object to the
/// target. The target type does not have to have a parameterless constructor,
/// as no new instance needs to be created.
///
/// Only the properties of the source and target types themselves
/// are taken into account, regardless of the actual types of the arguments.
/// Type of the source
/// Type of the target
/// Source to copy properties from
/// Target to copy properties to
public static void Copy(TSource source, TTarget target)
where TSource : class
where TTarget : class
{
PropertyCopier.Copy(source, target);
}
}
///
/// 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.
///
public static class PropertyCopy where TTarget : class, new()
{
///
/// Copies all readable properties from the source to a new instance
/// of TTarget.
///
public static TTarget CopyFrom(TSource source) where TSource : class
{
return PropertyCopier.Copy(source);
}
}
///
/// 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.
/// Note that this type we do not have a constructor constraint on TTarget, because
/// we only use the constructor when we use the form which creates a new instance.
///
internal static class PropertyCopier
{
///
/// Delegate to create a new instance of the target type given an instance of the
/// source type. This is a single delegate from an expression tree.
///
private static readonly Func creator;
///
/// List of properties to grab values from. The corresponding targetProperties
/// list contains the same properties in the target type. Unfortunately we can't
/// use expression trees to do this, because we basically need a sequence of statements.
/// We could build a DynamicMethod, but that's significantly more work :) Please mail
/// me if you really need this...
///
private static readonly List sourceProperties = new List();
private static readonly List targetProperties = new List();
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 BuildCreator()
{
ParameterExpression sourceParameter = Expression.Parameter(typeof(TSource), "source");
var bindings = new List();
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>(initializer, sourceParameter).Compile();
}
}
}
#endif
c#
linq-to-sql
Автоматически применять значения свойств одного объекта к другому того же типа?
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.