2013-08-12 9 views
5

Ho una vasta raccolta di oggetti generati automaticamente. Sebbene siano tutte di classi diverse e non correlate, tutti gli oggetti condividono alcune proprietà di base (nome, ID, ecc.). Non controllo la generazione di questi oggetti, quindi sfortunatamente non riesco ad adottare l'approccio ideale per implementare un'interfaccia. Vorrei creare un metodo in cui passo uno di questi oggetti arbitrario e faccio qualcosa usando queste proprietà comuni.Metodo per gestire oggetti con proprietà in comune, ma tipi di oggetti diversi

L'idea generale sarebbe qualcosa di simile:

someObj a = new someObj(); 
a.name = "sara"; 
diffObj b = new diffObj(); 
b.name = "joe"; 
string phrase = string.Format("I am with {0} and {1}", 
    getName(a), getName(b)); 

private string getName(object anyObjWithName) 
{ 
    return anyObjWithName.name; 
} 

anche se, naturalmente, questo non funziona.

Ho pensato che un metodo generico potesse contenere la risposta, ma l'unico modo che posso vedere per chiamarlo con il tipo corrente è usare genericMethod.Invoke, che continua a comportare lo stesso problema di non essere in grado di risolvere le proprietà dell'oggetto passato nel metodo. Questo è diverso da Calling generic method with a type argument known only at execution time o How to call generic method with a given Type object? in cui solo il tipo o le proprietà del tipo vengono utilizzate nel metodo, al contrario delle proprietà dell'oggetto.

Sono consapevole che questo sarebbe (molto) incline all'errore, ma posso garantire che tutti gli oggetti incontrati avranno le proprietà comuni che vengono manipolate.

+5

Utilizzare un'interfaccia? – Michael

+0

Provare a dichiarare un'interfaccia per correlare gli oggetti con le proprietà comuni o utilizzare la riflessione. – Nayan

+1

http://msdn.microsoft.com/en-us/library/64syzecx.aspx – Crisfole

risposta

9

posso garantire che tutti gli oggetti incontrati avrà le proprietà comuni manipolati

Se questo è il caso, è possibile utilizzare dynamic:

private string getName(dynamic anyObjWithName) 
{ 
    return anyObjWithName.name; 
} 

essere consapevoli del fatto che l'uso di qualsiasi oggetto che non ha una proprietà name non avrà esito negativo fino all'ora di esecuzione.

Se si desidera aggiungere un po 'di sicurezza si può prendere il RuntimeBinderException che viene generata se la proprietà non esiste:

private string getName(dynamic anyObjWithName) 
{ 
    try { 
     return anyObjWithName.name; 
    } 
    catch(RuntimeBinderException) { 
     return "{unknown}"; 
    } 
} 
+0

Cool, non ho mai visto questa soluzione ... – ganders

+3

Per il mio $ .02, non penso che l'OP sia in grado di iniziare il percorso 'dinamico'. La strada è irta di pericoli e questa risposta non è affatto pedagogica. –

+1

Sapevo di esserci addosso un po 'di dolore. Poiché non riesco a implementare un'interfaccia, non sono sicuro che ci sia un'altra opzione. – MaxPRafferty

0

Si sta creando un dispositivo di Rube Goldberg lì. Dovresti semplicemente avere tutte le classi degli oggetti dati che implementano una singola interfaccia, quindi puoi lavorarci su. Molto più semplice e meno incline agli errori che a manipolare la riflessione.

Il fatto stesso che molti oggetti abbiano proprietà comuni ma non condividono la stessa discendenza, almeno un'interfaccia comune, mostra che c'è qualcosa di sbagliato nella progettazione. Rifletti.

+2

Questo è davvero il punto in cui arriva il problema: non controllo la generazione degli oggetti. Il mio regno per un'interfaccia! – MaxPRafferty

0

diversi modi per ottenere questo risultato, più semplice, probabilmente è quello di creare l'interfaccia e dichiarare metodi comuni là, avere il vostro oggetto attuarlo, quindi cambiare "getName" metodo prende l'interfaccia oggetto

private string getName(IMyInterface anyObjWithName) 
{ 
    return anyObjWithName.name; 
} 
0

Il modo corretto per farlo è con un'interfaccia, se si possiede i tipi che si sta lavorando con

public interface IEntity 
{ 
    int ID { get; set; } 
    string Name { get; set; } 
} 

public class TypeOne : IEntity 
{ 
    public int ID { get; set; } 
    public string Name { get; set } 

    public string BespokePropertyOne { get; set;} 
} 

public class TypeTwo : IEntity 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public float BespokePropertyTwo { get; set; } 
} 

static void Main(string[] args) 
{ 
    List<IEntity> entities = new List<IEntity>(); 
    entities.Add(new TypeOne() { ID = 1, Name = "Bob", BespokePropertyOne = "blablabla" }); 
    entities.Add(new TypeTwo() { ID = 2, Name = "Alice", BespokePropertyTwo = 5.4f }); 

    foreach (IEntity entity in entities) 
    { 
     Console.WriteLine("ID: {0} Name: {1}", entity.ID, entity.Name); 
    } 
} 
+0

OP non ha un modo per controllare le classi. È menzionato in questione. – nawfal

0

questa risposta è stata scritta prima della modifica alla domanda affermando che le interfacce non erano possibile in questo caso. Forse può aiutare qualcun altro a leggere questa domanda.

Interfaccia:

interface Iname 
{ 
    string Name { get; set; } 
} 

Uso dell'interfaccia:

class A : Iname 
{ 
    public string Name { get; set; } 
} 

class B : Iname 
{ 
    public string Name { get; set; } 
} 

Il metodo:

string GetName(Iname o) 
{ 
    return o.Name; 
} 

Usa:

A a = new A { Name = "First" }; 
B b = new B { Name = "Last" }; 
Text = GetName(a) + " " + GetName(b); 
+0

OP non ha un modo per controllare le classi. È menzionato in questione. – nawfal

2

Se non sei soddisfatto delle prestazioni usando la dinamica come menzionato da D Stanley, puoi sempre provare FastMember.

Tutto quello che devi sapere per iniziare a usarlo è praticamente mostrato nei primi 2 esempi di codice.

+0

Wow, sì, questa libreria esiste letteralmente per risolvere questo esatto problema. Mi chiedo come funziona sotto il cofano senza riflessi ... – MaxPRafferty

+1

@MaxPRafferty: IIRC, farà leva sulla riflessione per ottenere le informazioni sui membri la prima volta, scriverà un IL equivalente in compilazione, quindi userà il codice compilato per il successivo accesso a tale tipo/utente. Ciò lo rende più vicino al codice compilato se confrontato con il frequente colpire il DLR o il riflesso. –

Problemi correlati