2012-10-19 23 views
6

en (baz arayüzü dahil) Aşağıdakilerin sınıf hiyerarşisi var diyelim:C# sınıfı bir hiyerarşide Derin Kopyalama/Klonlama yöntemleri - Her yerde somut bir uygulamaya ihtiyacım var mı?

Şimdi
IAction -> (abstract) BaseAction -> (concrete) ImmediateAction -> (concrete) MovementAction 

, en IAction bir yöntem sunar diyelim (kuyu, gerçekten farklı bir arayüz IAction uygular ama burada basit şeyler devam edelim gelmez!) :

// Returns a new IAction instance deep copied from the current instance. 
IAction DeepClone(); 

Şimdiye kadar iyi mi? Bizim derin kopyalama yöntemi var ve ImmediateAction o DeepClone() arasında sadece bir uygulama sağlayacaktır yüzden kopyalanan istediği bazı özelliklere sahiptir, fakat aynı zamanda bir kopyası yapıcısı: Artık

//Base Action implementation 
protected BaseAction(BaseAction old) 
{ 
    this.something = old.something; 
} 

//Immediate Action Implementation 
protected ImmediateAction(ImmediateAction old) 
    : base(old) 
{ 
    this.anything = old.anything; 
} 

public IAction DeepClone() 
{ 
    return new ImmediateAction(this); 
} 

, en MovementAction yok diyelim İçerisinde DeepClone() ile ilgili olan hiçbir şey yoktur, bu nedenle yöntemi veya kopya kurucuyu uygulamamaktadır. Yeni ImmediateAction örneklemek, bu yüzden ImmediateAction.DeepClone() yerine denir, MovementActionDeepClone() uygulamıyor - Burada neler olduğunu anlamak Şimdi

IAction x = new MovementAction(); 
IAction y = x.DeepClone(); 

//pleaseBeTrue is false 
bool pleaseBeTrue = y is MovementAction; 

: yaşıyorum

sorun budur. Bu nedenle, yukarıdaki örnekte y türü MovementAction yerine ImmediateAction şeklindedir.

Bu uzun girişten sonra sorum şu: Bu tür bir durum için en iyi uygulama nedir? Sıkışmış mıyım 'un yönteminiyöntemini uygulamak için hiyerarşisi boyunca her sınıf için ne olursa olsun? Burada yanlış kullandığım desen var ve daha iyi bir yolu var mı?

Son bir not: Eğer mümkün olursa yansıma yapmaktan kaçınmak istiyorum.

+0

Neden yansımayı önlemek istersiniz? –

+0

Bu bir oyunda, ve potansiyel olarak oyun sırasında değil, sadece yükleme sırasında kullanılıyor, bu yüzden eğer mümkün olursa yansıma tepesinden kaçınmak istiyorum. Biraz arka plan: Genellikle, JSON/XML tanımları aracılığıyla şeyler yüklenir, ancak IAction fabrikası (ve diğer fabrikalar) önbellekleri türüne göre önbellekler ve yeniden yükleme için XML'e geri gitmekten kaçınmak için saklanan referansı klonlar.(Havuzlama başka bir seçenekdi, ancak birçok farklı türdeki eylemlerle, hepsi farklı özelliklere sahipti ve bu yüzden yüzlerce farklı havuz olmaksızın bir havuzlama çözümünü göremiyorum) – Terminal8

+0

Bana bir niyet meselesi gibi görünüyor. Bir şeyi 'IAction' olarak ele almayı planlıyorsanız ve 'DeepClone' olarak adlandırdığınız nesnelerin orijinal türünü korumak önemlidir, 'DeepClone'u,' IAction'ı uygulayan tüm bu somut sınıflara yazarsınız. 've bu, yaratılan doğru nesneyi elde etmenizi sağlayacaktır. Neyse ki, bunları yazmak önemsiz. – itsmatt

cevap

2

kullanarak ve artımsal klonlama yapmak

public static class DeepCopyExt 
{ 
    public static T DeepCopy<T>(this T item) 
     where T : ThingBase, new() 
    { 
     var newThing = new T(); 
     item.CopyInto(newThing); 
     return newThing; 
    } 
} 

public abstract class ThingBase 
{ 
    public int A { get; set; } 

    public virtual void CopyInto(ThingBase target) 
    { 
     target.A = A; 
    } 
} 

public class ThingA : ThingBase 
{ 
} 

public class ThingB : ThingA 
{ 
    public int B { get; set; } 

    public override void CopyInto(ThingBase target) 
    { 
     var thingB = target as ThingB; 

     if(thingB == null) 
     { 
      throw new ArgumentException("target is not a ThingB"); 
     } 

     thingB.B = B; 
     base.CopyInto(thingB); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var b = new ThingB 
     { 
      A = 1, 
      B = 3 
     }; 

     //c is ThingB 
     var c = b.DeepCopy(); 

     var b1 = new ThingA 
     { 
      A = 1, 
     }; 

     //c1 is ThingA 
     var c1 = b1.DeepCopy(); 

     Debugger.Break(); 
    } 
} 
+0

bir az var! Bu çözümü gibi, söylemek zorunda sınıf başına uygulamak için bir şey ('' DeepClone' ve bir kopya oluşturucu yerine] ve nesne birleştirme, bir milyon 'DeepClone()' s yayılmak yerine tek bir konuma koyar, böylece havuzlama olabilir daha kolay bir ek! Teşekkürler! – Terminal8

0

Genellikle klon yönteminizi beton sınıflarında uygulamanız gerekir.

return new ImmediateAction(this); 
+0

Ah, bu benim hatamdı. Anında soyut değildir. – Terminal8

2

Yani evet, iki seçeneğiniz vardır: en üstteki dediğim gibi Aslında sen ImmediateAction eğer derlemek Yollanan bu kod soyut

  • Ya) her seferinde DeepClone (uygulamak ve ayrıntıları (listeye her paylaşılmayan özellikleri)
  • Veya kullanmak içinde 'hızlı & kirli' ancak paylaşılan uygulama bir uzantısı yöntemi kullanmak Could yansıma
İlgili konular