Есть ли что-то встроенное в .NET / C # для копирования значений между объектами? - PullRequest
10 голосов
/ 23 января 2012

Предположим, у вас есть 2 класса, например:

public class ClassA {
    public int X { get; set; }
    public int Y { get; set; }
    public int Other { get; set; }
}

public class ClassB {
    public int X { get; set; }
    public int Y { get; set; }
    public int Nope { get; set; }
}

Теперь представьте, что у вас есть экземпляр каждого класса, и вы хотите скопировать значения из a в b. Есть ли что-то вроде MemberwiseClone, которое будет копировать значения, в которых имена свойств совпадают (и, конечно, отказоустойчиво - у одного есть get, а у другого набор и т. Д.)?

var a = new ClassA(); var b = new classB();
a.CopyTo(b); // ??

Что-то вроде этого довольно легко на языке, подобном JavaScript.

Полагаю, ответ - нет, но, возможно, есть и простая альтернатива. Я написал для этого библиотеку отражений, но если ее встроить в C # / .NET на более низком уровне, вероятно, будет более эффективным (и зачем заново изобретать колесо).

Ответы [ 4 ]

10 голосов
/ 23 января 2012

Нет ничего в структуре для сопоставления объект-объект, но есть очень популярная библиотека, которая делает это: AutoMapper .

AutoMapper - простая маленькая библиотека, созданная длярешить обманчиво сложную проблему - избавиться от кода, который отображает один объект на другой.Этот тип кода довольно скучно и скучно писать, так почему бы не изобрести инструмент, который сделает это для нас?

Кстати, просто для изучения, вот простой так, как вы можете реализовать то, что вы хотите.Я не проверил это полностью, и он нигде не является таким надежным / гибким / производительным, как AutoMapper, но, надеюсь, есть что-то, что можно извлечь из общей идеи:

public void CopyTo(this object source, object target)
{
    // Argument-checking here...

    // Collect compatible properties and source values
    var tuples = from sourceProperty in source.GetType().GetProperties()
                 join targetProperty in target.GetType().GetProperties() 
                                     on sourceProperty.Name 
                                     equals targetProperty.Name

                 // Exclude indexers
                 where !sourceProperty.GetIndexParameters().Any()
                    && !targetProperty.GetIndexParameters().Any()

                 // Must be able to read from source and write to target.
                 where sourceProperty.CanRead && targetProperty.CanWrite

                 // Property types must be compatible.
                 where targetProperty.PropertyType
                                     .IsAssignableFrom(sourceProperty.PropertyType)

                 select new
                 {
                     Value = sourceProperty.GetValue(source, null),
                     Property = targetProperty
                 };

    // Copy values over to target.
    foreach (var valuePropertyTuple in tuples)
    {
        valuePropertyTuple.Property
                          .SetValue(target, valuePropertyTuple.Value, null);

    }
}
1 голос
/ 23 января 2012

В .NET нет ничего подобного, о котором я знаю, но одна библиотека, которая способна сделать это (и многое другое), это AutoMapper . Для вашего случая что-то вроде:

_mapper.Map<A, B> (a, b);
0 голосов
/ 23 января 2012

См. Интерфейс System.ICloneable и метод System.Object.MemberwiseClone().Как отмечено в документах MSDN,

Метод MemberwiseClone создает поверхностную копию путем создания нового объекта, а затем копирует нестатические поля текущего объекта в новый объект.Если поле является типом значения, выполняется побитовая копия поля.Если поле является ссылочным типом, ссылка копируется, а ссылочный объект - нет;следовательно, исходный объект и его клон ссылаются на один и тот же объект.
0 голосов
/ 23 января 2012

Насколько я знаю, этого не существует. Я делал это так:

public static T DeepCopy(T oldclass)
{
    using (MemoryStream stream = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, oldclass);
        ms.Position = 0;
        return (T)formatter.Deserialize(stream);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...