2017-02-02 16 views
2

Я хотел создать более ограниченную версию MemberwiseClone, но реализовал единственный способ, которым мой собственный код C# может добавлять свойства к объекту, заключается в использовании dynamic, но это не может дать объекту тот же тип, что и оригинал. Мой другой, более уродливый выбор - испустить источник для нового клона и скомпилировать его во время выполнения, но это сопряжено с сложностями re. ссылки на сборку и т. д., которые мне не нужны, чтобы все было просто.Как MemberWiseClone создает новый объект с клонированными свойствами?

На данный момент я просто использую MemberwiseClone, но мне действительно интересно, как это работает. Я не могу найти какой-либо декомпилированный источник.

+1

Вам не нужен декомпилятор для этих дней. Источник [источник ссылки] (https://referencesource.microsoft.com/#mscorlib/system/object.cs,1556d8bb3f97be20) сообщит вам, что этот метод реализуется самой средой выполнения (MethodImplOptions.InternalCall). Оттуда вы направляетесь к репозиторию CoreClr github и выполняете поиск своего звонка. В вашем случае вы в конечном итоге найдете [этот файл] (https://github.com/dotnet/coreclr/blob/master/src/classlibnative/bcltype/objectnative.cpp), который содержит интересующую вас реализацию (ObjectNative: : Clone). – thehennyy

+0

Спасибо, @thehennyy, теперь я больше знаю, как найти материал в ссылочном коде, но мой C++ примерно на десять лет отстает от меня, и я не знаю, что делает ObjectNative :: Clone'. Все, что я хочу знать с этим вопросом, - это то, какой принцип используется для клонирования объекта. Видя, что это C++, он делает прямой байт для копии байта или что? – ProfK

+0

Кто в мире мог бы найти этот вопрос «слишком широким» и проголосовать за закрытие? Я задаю один очень конкретный вопрос, который может иметь только очень ограниченный набор ответов. Название - вопрос; прочитайте его манекен. – ProfK

ответ

8

Это в основном объясняется в MemberwiseClone MSDN documentation:

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

Фактическая реализация вышеуказанного реализована внутри CLR. Вы можете думать об этом как оптимизированном варианте следующих стандартных C# код:

using System.Reflection; 
using System.Runtime.Serialization; 

public static object CustomMemberwiseClone(object source) 
{ 
    var clone = FormatterServices.GetUninitializedObject(source.GetType()); 
    for (var type = source.GetType(); type != null; type = type.BaseType) 
    { 
     var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); 
     foreach (var field in fields) 
      field.SetValue(clone, field.GetValue(source)); 
    } 
    return clone; 
} 

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

Опять же, фактическая внутренняя реализация отличается (как указано в комментариях), приведенный выше фрагмент - это просто продемонстрировать принцип и как вы можете реализовать метод с той же семантикой через отражение (что, конечно, будет намного медленнее чем метод CLR).

ADDED BY OP: Пожалуйста, см. Комментарии Ивана ниже для дальнейшего объяснения, которое я искал. Я рассматриваю эту часть его ответа и принимаю его на основе их.

+0

Спасибо, я понимаю, что, хотя я даже написал код, чтобы сделать это сам, чтобы были скопированы только объявленные, публичные и не коллекционные свойства, а не поля, - мои модели подробного представления должны иметь только простые свойства, но все, о чем я прошу, в терминах высокого уровня, как метод CLR делает это внутренне, т. е. является ли он двоичным, байтом для копии байта или что? – ProfK

+1

В основном используется память низкого уровня (байты). Подобно присваиванию переменной 'struct'. –

+2

С особым вниманием к GC Refs (указатели) внутри, но опять же, ничего, кроме, например, копирования 'struct' с' string' внутри. В любом случае, теперь я вижу, что мой ответ не затрагивает ваш вопрос, поэтому я собираюсь удалить его. –