генератор конструктора копирования c # - PullRequest
6 голосов
/ 26 марта 2010

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

Например:

PushPin newValPushPin = oldPushPin; //I want to break the reference here.

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

  1. Есть ли лучший способ присвоить объект другому объекту по значению?
  2. Если нет, есть ли генератор конструктора копирования?

Примечание : ICloneable недоступно в Silverlight.

Ответы [ 9 ]

6 голосов
/ 26 марта 2010

Если вы можете пометить объект, который должен быть клонирован, как Сериализуемый, то вы можете использовать сериализацию в памяти для создания копии. Проверьте следующий код, у него есть то преимущество, что он будет работать и с другими типами объектов, и вам не нужно менять конструктор копирования или код копирования каждый раз, когда свойство добавляется, удаляется или изменяется:

    class Program
    {
        static void Main(string[] args)
        {
            var foo = new Foo(10, "test", new Bar("Detail 1"), new Bar("Detail 2"));

            var clonedFoo = foo.Clone();

            Console.WriteLine("Id {0} Bar count {1}", clonedFoo.Id, clonedFoo.Bars.Count());
        }
    }

    public static class ClonerExtensions
    {
        public static TObject Clone<TObject>(this TObject toClone)
        {
            var formatter = new BinaryFormatter();

            using (var memoryStream = new MemoryStream())
            {
                formatter.Serialize(memoryStream, toClone);

                memoryStream.Position = 0;

                return (TObject) formatter.Deserialize(memoryStream);
            }
        }
    }

    [Serializable]
    public class Foo
    {
        public int Id { get; private set; }

        public string Name { get; private set; }

        public IEnumerable<Bar> Bars { get; private set; }

        public Foo(int id, string name, params Bar[] bars)
        {
            Id = id;
            Name = name;
            Bars = bars;
        }
    }

    [Serializable]
    public class Bar
    {
        public string Detail { get; private set; }

        public Bar(string detail)
        {
            Detail = detail;
        }
    }
3 голосов
/ 26 марта 2010

Существует защищенный член с именем " MemberwiseClone ", вы можете написать это в своем классе ...

public MyClass Clone(){
   return (MyClass)this.MemberwiseClone();
}

тогда вы можете получить доступ ..

MyClass newObject = oldObject.Clone();
2 голосов
/ 26 марта 2010

Единственный способ (который я знаю) сделать это и сделать это правильно, это реализовать копию самостоятельно.Возьмем для примера:

public class FrobAndState
{
  public Frob Frobber { get; set;}
  public bool State { get; set; }
}
public class Frob
{
  public List<int> Values { get; private set; }
  public Frob(int[] values)
  {
    Values = new List<int>(values);
  }
}

В этом примере вам нужно знать , как реализован Frob, т.е. тот факт, что вам нужно вызвать конструктор, чтобы создать его копию какЗначения доступны только для чтения, чтобы иметь возможность сделать копию данного экземпляра FrobAndState.

Кроме того, вы не можете просто реализовать FrobAndState.Copy таким образом:

public class FrobAndState
{
  // ... Properties

  public FrobAndState Copy()
  {
     var new = new FrobAndState();
     new.State = this.State;
     new.Frobber = this.Frobber;
  }
}

Поскольку обаэкземпляр FrobAndState, для которого вы вызвали .Copy (), и новый экземпляр будут иметь ссылку на один и тот же экземпляр Frobber.

Короче говоря, копирование - это hard и любойРеализовать копирование сложно.

1 голос
/ 26 марта 2010

C # не имеет конструктора копирования . Есть разные способы решения этой проблемы. На уровне ООП вы можете использовать наследование или агрегацию. AutoMapper также стоит попробовать.

0 голосов
/ 26 марта 2010

Вы реализуете метод клонирования объектов Джастином Анхелем в Silverlight

с использованием системы;

с использованием System.Reflection;

с использованием System.Windows;

пространство имен JustinAngelNet.Silverlight.Framework

{

public static class SilverlightExtensions

{

    public static T Clone<T>(T source)
    {
        T cloned = (T) Activator.CreateInstance(source.GetType());

        foreach (PropertyInfo curPropInfo in source.GetType().GetProperties())
        {
            if (curPropInfo.GetGetMethod() != null
                && (curPropInfo.GetSetMethod() != null))
            {
                // Handle Non-indexer properties
                if (curPropInfo.Name != "Item")
                {
                    // get property from source
                    object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] {});

                    // clone if needed
                    if (getValue != null && getValue is DependencyObject)
                        getValue = Clone((DependencyObject) getValue);

                    // set property on cloned
                    if (getValue != null)
                    curPropInfo.GetSetMethod().Invoke(cloned, new object[] {getValue});
                }
                    // handle indexer
                else
                {
                    // get count for indexer
                    int numberofItemInColleciton =
                        (int)
                        curPropInfo.ReflectedType.GetProperty("Count").GetGetMethod().Invoke(source, new object[] {});

                    // run on indexer
                    for (int i = 0; i < numberofItemInColleciton; i++)
                    {
                        // get item through Indexer
                        object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] {i});

                        // clone if needed
                        if (getValue != null && getValue is DependencyObject)
                            getValue = Clone((DependencyObject) getValue);
                        // add item to collection
                        curPropInfo.ReflectedType.GetMethod("Add").Invoke(cloned, new object[] {getValue});
                    }
                }
            }
        }

        return cloned;
    }
}

}

Тогда вы можете сделать это

MyClass newObject = SilverlightExtensions.Clone (oldObject);

0 голосов
/ 26 марта 2010

Хотя, это может не ответить на ваш вопрос напрямую, но добавить цент; обычно термин Clone связан с мелкой копией (ссылочные объекты). Я полагаю, что для получения глубокой копии вам нужно изучить некий творческий шаблон ( prototype ?) Ответ на этот вопрос может помочь.

0 голосов
/ 26 марта 2010

Если вы хотите выполнить копирование при назначении, вы должны использовать struct вместо class. Но будьте осторожны, легко совершать тонкие ошибки. Настоятельно рекомендуется, чтобы все элементы были неизменными, чтобы уменьшить вероятность ошибки.

0 голосов
/ 26 марта 2010

Если вы сделаете свой класс Serializable, вы можете Serialize превратить его в MemoryStream и Deserialize в новый экземпляр.

0 голосов
/ 26 марта 2010

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

Что вы подразумеваете под «с заданием»? Если вы имеете в виду, что вы хотите, чтобы люди могли сказать:

a = b;

И для вас, чтобы определить, что означает =, единственный способ сделать это в C # - это если b отличается от a, и вы определили неявное преобразование (или более осторожно, если a обозначает что-то вида x.Y, где Y - это свойство с установщиком). Вы не можете переопределить = для простого присвоения идентичных типов в C #.

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

Если это действительно так, то я думаю, у вас другая проблема. Ваш класс слишком большой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...