Diciamo che ho il seguente codice che aggiorna un campo di un struct
usando il riflesso. Poiché l'istanza della struct viene copiata nel metodo DynamicUpdate
, it needs to be boxed to an object before being passed.Generare il metodo dinamico per impostare un campo di una struct invece di utilizzare la riflessione
struct Person
{
public int id;
}
class Test
{
static void Main()
{
object person = RuntimeHelpers.GetObjectValue(new Person());
DynamicUpdate(person);
Console.WriteLine(((Person)person).id); // print 10
}
private static void DynamicUpdate(object o)
{
FieldInfo field = typeof(Person).GetField("id");
field.SetValue(o, 10);
}
}
Il codice funziona correttamente. Ora, diciamo che non voglio usare il riflesso perché è lento. Invece, voglio generare alcuni CIL direttamente modificando il campo id
e convertire tale CIL in un delegato riutilizzabile (ad esempio, utilizzando la funzione Metodo dinamico). Specialmente, voglio sostituire il codice precedente con s/t in questo modo:
static void Main()
{
var action = CreateSetIdDelegate(typeof(Person));
object person = RuntimeHelpers.GetObjectValue(new Person());
action(person, 10);
Console.WriteLine(((Person)person).id); // print 10
}
private static Action<object, object> CreateSetIdDelegate(Type t)
{
// build dynamic method and return delegate
}
La mia domanda: esiste un modo per implementare CreateSetIdDelegate
stralci da utilizzando uno dei seguenti tecniche?
- Genera CIL che richiama il setter utilizzando reflection (come il primo segmento di codice in questo post). Questo non ha senso, dato che il requisito è quello di sbarazzarsi della riflessione, ma è una possibile implementazione, quindi cito.
- Invece di utilizzare
Action<object, object>
, utilizzare un delegato personalizzato la cui firma èpublic delegate void Setter(ref object target, object value)
. - Invece di utilizzare
Action<object, object>
, utilizzareAction<object[], object>
con il primo elemento dell'array come oggetto di destinazione.
La ragione per cui non mi piace 2 & 3 è perché io non voglio avere i delegati diversi per il setter di oggetto e setter di struct (così come non volendo fare il set-oggetto-campo delegare più complicato del necessario, ad es. Action<object, object>
). Suppongo che l'implementazione di CreateSetIdDelegate
genererebbe CIL diversi a seconda che il tipo di destinazione sia struct o object, ma voglio che restituisca lo stesso delegato che offre la stessa API all'utente.
sta usando una struct mutabile * veramente * la scelta migliore qui? È quasi sempre un dolore per molte ragioni, e sembra che tu stia correndo in alcune di esse ... –
Hai considerato di compilare un albero di espressioni invece di emettere IL? Dovrebbe essere molto più facile –
@Jon: in realtà sto costruendo un'API di riflessione veloce (http://fasterflect.codeplex.com/) in modo che il supporto per le operazioni di struct reflection sia auspicabile da alcune persone. –