Domanda

Su C # 3.0 e .NET 3.5, immagina che ci sia un'interfaccia:

public interface INameable
{
  string Name {get;}
}

e molte classi immutabili che implementano l'interfaccia.

Vorrei avere un unico metodo di estensione

public static T Rename<T>(this T obj) where T : INameable
{ 
  ...
}

che restituisce un'istanza di wrapping dell'oggetto originale con solo il nome modificato e tutte le altre proprietà leggono e le chiamate di metodo vengono instradate all'oggetto originale.

Come ottenere una classe wrapper generica per questo, senza implementarla per tutti i tipi di implementazione INameable? Pensi che sia possibile?

È stato utile?

Soluzione

No, questo non è possibile, a meno che T non sia vincolato a essere un'interfaccia o a essere una classe con tutti i membri virtuali, e questo vincolo non è possibile specificare al momento della compilazione (sebbene potresti scrivere un controllo di runtime se sei soddisfatto di questo approccio).

Il motivo per cui non è possibile farlo per tipi arbitrari è che se si prende un oggetto di tipo T , è necessario restituire un oggetto assegnabile a T . Se passo un oggetto che appare come segue ...

public sealed class SomeClass : INameable
{
    public string Name { get; }
    public string Abc { get; }
}

... quindi non è possibile creare un altro tipo assegnabile a SomeClass . Non usando Reflection.Emit o qualsiasi altro metodo, perché il tipo è sigillato.

Tuttavia, se sei soddisfatto delle restrizioni che ho citato, puoi usare qualcosa come il framework Castle DynamicProxy per creare un tipo che inoltra l'oggetto passato e intercetta le chiamate per inoltrarle o reimplementarle come . appropriato

Altri suggerimenti

Beh, sì, è possibile, ma implica la generazione di codice in memoria.

Puoi guardare Reflection.Emit e qui .

Nota che coinvolgerà molto codice.

Cioè, se presumo che ti capisca correttamente.

Ecco cosa penso che tu stia chiedendo:

SomeNameableObject a1 = new SomeNameableObject("ThisIsTheFirstName");
SomeNameableObject a2 = a1.Rename("ThisIsTheSecondName");
// a1 works, still has the name ThisIsTheFirstName
// a2 works, but everything is routed to a1,
//    except for the name, which is ThisIsTheSecondName

È corretto?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top