c#copy构造函数生成器

时间:2010-03-26 08:45:58

标签: c# silverlight

我想将值从一个对象复制到另一个对象。类似于传递值但具有赋值的东西。

例如:

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

我被告知要为此编写一个复制构造函数。但是这个类有很多属性,手工编写复制构造函数可能需要一个小时。

  1. 有没有更好的方法通过值将对象分配给另一个对象?
  2. 如果没有,是否有复制构造函数生成器?
  3. 注意:Silverlight中没有ICloneable。

9 个答案:

答案 0 :(得分:6)

如果可以将要克隆的对象标记为Serializable,则可以使用内存中序列化来创建副本。检查以下代码,它的优点是它也适用于其他类型的对象,并且每次添加,删除或更改属性时都不必更改复制构造函数或复制代码:

    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;
        }
    }

答案 1 :(得分:3)

有一个名为“MemberwiseClone”的受保护成员,您可以在班上写这个......

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

然后你可以访问..

MyClass newObject = oldObject.Clone();

答案 2 :(得分:2)

执行此操作并且正确执行的唯一方法(我知道)是自己实现副本。举个例子:

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是如何实现的,即您需要调用构造函数来创建它的副本,因为Values是只读的,才能够制作给定FrobAndState实例的副本。

另外 - 你不能只是实现FrobAndState.Copy:

public class FrobAndState
{
  // ... Properties

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

因为您调用.Copy()的FrobAndState实例和新实例都会引用同一个Frobber实例。

简而言之,复制内容是 hard ,任何复制实现都很难做到。

答案 3 :(得分:1)

C# does not have a copy constructor。有不同的方法来解决这个问题。在OOP级别,您可以使用继承或聚合。 AutoMapper也可能值得一试。

答案 4 :(得分:0)

  

我想从一个对象复制值   到另一个对象。类似的东西   通过值传递但是通过赋值。

“分配”是什么意思?如果你的意思是你希望人们能够说:

a = b;

并且为了定义=的含义,在C#中唯一可以做到这一点的方法是b是与a不同的类型,并且您已经定义了隐式转换(或者更重要的是,如果a代表x.Y形式的某些内容,其中Y是带有setter的属性。对于C#中相同类型之间的简单分配,您无法覆盖=

  

我被告知要写一个复制构造函数   为了这。但这个班级有很多   属性,它可能需要一个   小时写一个拷贝构造函数   手。

如果这是真的,那么我猜你有不同的问题。你的班级太大了。

答案 5 :(得分:0)

如果你上课Serializable,可以Serialize将其MemoryStreamDeserialize改为新实例。

答案 6 :(得分:0)

如果您想要分配时复制,则应使用struct代替class。但要小心,很容易犯下微妙的错误。强烈建议所有结构都是不可改变的,以减少出错的可能性。

答案 7 :(得分:0)

虽然,这可能不会直接回答你的问题,但要增加一分钱;通常,术语Cloneshallow copy(引用的对象)相关联。要获得深层副本,我相信你需要研究一些创作模式(prototype?)。 this question的答案可能会有所帮助。

答案 8 :(得分:0)

你实现了Justin Angel在Silverlight中克隆对象的方法

使用System;

使用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);