Załóżmy, że mam następujący kod, który aktualizuje pole przy użyciu odbicia. Ponieważ instancja struct jest kopiowana do metody DynamicUpdate
, it needs to be boxed to an object before being passed.Generowanie dynamicznej metody ustawiania pola struktury struct zamiast używania refleksji
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);
}
}
Kod działa poprawnie. Teraz powiedzmy, że nie chcę korzystać z refleksji, ponieważ jest powolna. Zamiast tego chcę wygenerować CIL bezpośrednio modyfikując pole id
i przekonwertować CIL na delegata wielokrotnego użytku (powiedzmy, używając funkcji dynamicznej metody). Specjalnie, chcę zastąpić powyższy kod z S/T to tak:
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
}
Moje pytanie: jest jakiś sposób, aby wdrożyć CreateSetIdDelegate
wyjątki od od użyciu jednej z następujących technik?
- Wygeneruj CIL, który wywołuje setera za pomocą odbicia (jako pierwszy segment kodu w tym wpisie). To nie ma sensu, biorąc pod uwagę, że trzeba pozbyć się refleksji, ale jest to możliwa implementacja, więc wspomnę tylko.
- Zamiast używać
Action<object, object>
, użyj niestandardowego przedstawiciela, którego podpis topublic delegate void Setter(ref object target, object value)
. - Zamiast używać
Action<object, object>
, należy użyćAction<object[], object>
, a pierwszym elementem tablicy będzie obiekt docelowy.
Powodem nie lubię 2 & 3 jest dlatego, że nie chcą mieć różne delegatów dla seter seter obiektu oraz od struktury (jak również nie chcąc, aby nastawioną-Object-field delegować bardziej skomplikowane niż to konieczne, np. Action<object, object>
). Sądzę, że implementacja CreateSetIdDelegate
wygenerowałaby różne CIL zależnie od tego, czy typem docelowym jest struktura czy obiekt, ale chcę, aby zwrócił tego samego delegata oferującego użytkownikowi ten sam interfejs API.
stosuje zmienny struct * naprawdę * Twój najlepszą opcją tutaj? To prawie zawsze ból z wielu powodów i wydaje się, że wpadłeś na niektóre z nich ... –
Czy rozważałeś skompilowanie drzewa wyrażeń zamiast emitowania IL? Powinno być znacznie łatwiej. –
@Jon: faktycznie buduję API szybkiego refleksji (http://fasterflect.codeplex.com/), więc wsparcie dla struktur refleksyjnych byłoby pożądane przez niektórych ludzi. –