2009-08-13 14 views
14

Ho lavorato con C# per molti anni, ma ho appena scoperto questo problema che mi ha bloccato, e davvero non so nemmeno come porre la domanda, quindi, per l'esempio!proprietà di interfaccia copia in C#

public interface IAddress 
{ 
    string Address1 { get; set; } 
    string Address2 { get; set; } 
    string City { get; set; } 
    ... 
} 

public class Home : IAddress 
{ 
    // IAddress members 
} 

public class Work : IAddress 
{ 
    // IAddress members 
} 

La mia domanda è, voglio copiare il valore delle proprietà IAddress da una classe all'altra. Questo è possibile in una semplice dichiarazione di una riga o devo ancora fare un incarico da proprietà a proprietà di ciascuno? In realtà sono abbastanza sorpreso che questa cosa apparentemente semplice mi abbia bloccato come se fosse ... Se non è possibile in modo conciso, qualcuno ha qualche scorciatoia che usano per fare questo genere di cose?

Grazie!

+0

Pensando che questo potrebbe essere un duplicato di http://stackoverflow.com/questions/563253/c-generic-copy-constructor. se non altro, dovrebbe rispondere alla tua domanda. –

risposta

2

Non esiste un solo rivestimento per questo.

Se lo si fa molto, è possibile esaminare una qualche forma di generazione del codice, magari utilizzando i modelli T4 e Reflection.

BTW COBOL ha una dichiarazione per questo: MOVE CORRISPONDING HOME TO WORK.

12

Si potrebbe costruire un metodo di estensione:

public static void CopyAddress(this IAddress source, IAddress destination) 
{ 
    if (source is null) throw new ArgumentNullException("source"); 
    if (destination is null) throw new ArgumentNullException("destination"); 

    //copy members: 
    destination.Address1 = source.Address1; 
    //... 
} 
+0

Mi piace molto questa soluzione. Grazie! – opedog

+2

Vedere la risposta seguente che ha un metodo di estensione generica che non è fragile quando l'interfaccia cambia o i metodi set/get vengono aggiunti/rimossi. – plinth

1

si avrebbe bisogno di creare un metodo per fare questo

public void CopyFrom(IAddress source) 
{ 
    this.Address1 = source.Address1; 
    this.Address2 = source.Address2; 
    this.City = source.city; 
} 
+0

Questo è un metodo fragile, che potrebbe interrompersi se vengono aggiunte nuove proprietà. – plinth

+0

Sì, molti modi, tranne se si utilizza la riflessione. Fare ciò di cui l'utente sta parlando è un'opzione valida. –

0

Si potrebbe avere un costruttore su ogni classe prendere un IAddress e hanno membri attuate popolata all'interno.

esempio

public WorkAddress(Iaddress address) 
{ 
    Line1 = IAddress.Line1; 
    ... 
} 

Per uso manutenibilità riflessione per ottenere i nomi delle proprietà.

HTH,

Dan

0

Se incapsulare le parti comuni l'indirizzo di casa e il lavoro in una classe separata che può rendere la vita più facile. Quindi puoi semplicemente copiare su quella proprietà. Questo mi sembra un design migliore.

In alternativa, è possibile suddividere una soluzione con riflessione e attributi in cui il valore delle proprietà in un oggetto viene copiato nelle proprietà corrispondenti (e contrassegnate) nell'altro. Naturalmente non sarà nemmeno una soluzione a una sola riga, ma potrebbe essere più veloce e più gestibile di altre se si dispone di un ampio set di proprietà.

2

Non credo che ci sia una soluzione linguistica pronta per questo (tutte le proprietà dovrebbero avere getter e setter).

È possibile creare Indirizzo come classe astratta, con un metodo Copia (Indirizzo aggiunto).

In alternativa, è possibile impostare Casa e lavoro su HAVE un IAddress e non estenderne uno. La copia sarebbe quindi immediata.

4

Jimmy Bogard AutoMapper è molto utile per questo tipo di operazione di mappatura.

+0

Apache Commons aveva una libreria chiamata "BeanUtils" che usavo quando sviluppavo in Java. Ciò che Martinho Fernandes suggerisce sembra essere la libreria .net corrispondente più vicina. –

18

Ecco un modo per farlo che non ha nulla a che fare con le interfacce:

public static class ExtensionMethods 
{ 
    public static void CopyPropertiesTo<T>(this T source, T dest) 
    { 
     var plist = from prop in typeof(T).GetProperties() where prop.CanRead && prop.CanWrite select prop; 

     foreach (PropertyInfo prop in plist) 
     { 
      prop.SetValue(dest, prop.GetValue(source, null), null); 
     } 
    } 
} 

class Foo 
{ 
    public int Age { get; set; } 
    public float Weight { get; set; } 
    public string Name { get; set; } 
    public override string ToString() 
    { 
     return string.Format("Name {0}, Age {1}, Weight {2}", Name, Age, Weight); 
    } 
} 

static void Main(string[] args) 
{ 
    Foo a = new Foo(); 
    a.Age = 10; 
    a.Weight = 20.3f; 
    a.Name = "Ralph"; 
    Foo b = new Foo(); 
    a.CopyPropertiesTo<Foo>(b); 
    Console.WriteLine(b); 
} 

Nel tuo caso, se si desidera solo un insieme di proprietà di interfaccia per copiare si può fare questo:

((IAddress)home).CopyPropertiesTo<IAddress>(b); 
+1

Probabilmente dovresti attaccare un vincolo lì - dove T: IAddress. Quindi è anche possibile memorizzare nella cache la ricerca di Reflection anziché eseguirla per ogni chiamata ed evitare comunque di dover aggiornare il metodo se l'interfaccia cambia. –

+0

BTW, capisco che stai cercando il caso più generale, ma in questo caso sembra che cerchi di usare una mazza per colpire un chiodo. –

+1

Il tuo codice si interromperà al runtime se 'source' e' dest' sono diversi tipi, che sono nella domanda originale. Puoi correggerlo ottenendo la lista delle proprietà da 'T' piuttosto che da' source'. Ad esempio: 'var plist = from prop in typeof (T) .GetProperties() dove prop.CanRead && prop.CanWrite select prop;' – LukeH