2013-08-05 4 views
0

Как я узнал, что не рекомендуется реализовывать ICloneable (due to the fact that it does not differentiate between Deep Copy or Shallow Copy), я пытаюсь определить, следует ли мне реализовать его как абстрактный или интерфейс.Реализация пользовательской функции клонирования/копирования: абстрактный или интерфейс?

Я чувствую, что моя реализация останется в основном той же самой, например. a binary deep copy и MemberwiseClone shallow copy, поэтому с этой целью я чувствовал, что абстрактный метод был бы идеальным. Тем не менее, я понимаю, что C# не выполняет множественное наследование, поэтому, если мне когда-либо понадобится использовать еще один абстрактный класс, то я больше не могу.

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

Говоря это, действительно ли используется интерфейс для сохранения абстрактного наследования для более важных вещей в моих клонируемых классах? Или есть другой способ сделать это?

В качестве альтернативы, действительно ли это (читать: не вонючий) для абстракции для реализации другого абстрактного? Это было бы моим предположением о том, чтобы обойти однонаследование, которое мешает мне реализовать класс CloneCapable, а также еще один абстрактный, но похоже, что это может быть сомнительным. например,

public abstract class CloneCapable 
{ 
    public object ShallowCopy() 
    { 
    // implementation 
    } 

    public object DeepCopy() 
    { 
    // implementation 
    } 
} 

public abstract class ClassA : CloneCapable {} 

// abstract-abstract since I can't do ClassB : ClassA, CloneCapable 
public abstract class ClassB : ClassA {} 

ответ

2

Я бы определенно сделал это интерфейсом. Причина в том, что интерфейсы должны быть очень , общие, и именно поэтому мы можем реализовать несколько интерфейсов. Если есть код котельной, который вы хотите написать, нет ничего, что помешало бы вам использовать как интерфейсы, так и абстрактные классы.

public interface ICustomCloneable<T> 
{ 
    T ShallowCopy(); 
    T DeepCopy(); 
} 

public abstract class CustomCloneable<T> ICustomCloneable<T> where T : class 
{ 
    public T ShallowCopy() { return ShallowCopy(this); } 
    public T DeepCopy() { return DeepCopy(this); } 

    // static helpers 
    public static object ShallowCopy(T obj) { /* boilerplate implementation */ } 
    public static object DeepCopy(T obj) { /* boilerplate implementation */ } 
} 


public class ClassA : CustomCloneable<ClassA> { /* Use boilerplate functionality */ } 
public class ClassB : SomeOtherClass, ICustomCloneable<ClassB> 
{ 
    // implement ICustomCloneable using static helpers 
    public ClassB ShallowCopy() { return CustomCloneable<ClassB>.ShallowCopy(this); } 
    public ClassB DeepCopy() { return CustomCloneable<ClassB>.DeepCopy(this); } 
} 

Я использовал здесь дженерики, но нет причин, по которым вам нужно ... Это может быть даже нежелательно. Такой подход позволяет писать шаблонный код, но не быть привязанными к ней:

public class ClassC : ICustomCloneable<ClassC> 
{ 
    public ClassC ShallowCopy() { /* Do special cloning for ClassC */ } 
    public ClassC DeepCopy() { /* Do special cloning for ClassC */ } 
} 
+0

Отличное понимание, я ценю его. – Arclight

0

Я думал, что создание интерфейса был путем, но потом я нашел this вопрос и первый ответ. Это прекрасный способ сделать клонирование, но я подумал, что это может очень хорошо сочетаться с Custom Extension Method, поэтому я написал код, основанный на коде в первом сообщении и на справочной странице MS:

Некоторые классы играть с:

[Serializable] 
public abstract class Base 
{ 
    public abstract int m1(); 
} 

[Serializable] 
public class derived : Base 
{ 
    public int a = 42; 
    public override int m1() 
    { 
     throw new NotImplementedException(); 
    } 
} 

класса с методом расширения на основе примеров кода из обоих linkes

//Extension methods must be defined in a static class 
public static class StringExtension 
{ 
    // This is the extension method. 
    // The first parameter takes the "this" modifier 
    // and specifies the type for which the method is defined. 
    public static T MyCloneExtension<T>(this T t) 
    { 
     // Code in this function was copied from https://stackoverflow.com/questions/78536/deep-cloning-objects-in-c-sharp 
     if (!typeof(T).IsSerializable) 
     { 
      throw new ArgumentException("The type must be serializable.", "source"); 
     } 

     // Don't serialize a null object, simply return the default for that object 
     if (Object.ReferenceEquals(t, null)) 
     { 
      return default(T); 
     } 

     IFormatter formatter = new BinaryFormatter(); 
     Stream stream = new MemoryStream(); 
     using (stream) 
     { 
      formatter.Serialize(stream, t); 
      stream.Seek(0, SeekOrigin.Begin); 
      return (T)formatter.Deserialize(stream); 
     } 
    } 
} 

и, наконец, вызова, чтобы клонировать объект

derived d = new derived(); 
derived d2 = d.MyCloneExtension<derived>(); 
Смежные вопросы