Способ преобразования между открытыми и закрытыми делегатами.

2

Мне нужно преобразовать открытый делегат (тот, в котором Target не указан) в закрытое. Я профилировал свой код, а стоимость использования CreateDelegate() для создания закрытого делегата для метода экземпляра представляет собой значительную долю ( > 60%) общего времени выполнения (как это имеет место для каждого нового экземпляра типа),

Некоторая базовая информация о открытых и закрытых делегатах описанная на сайте MSDN в документации для CreateDelegate.

Мой текущий подход заключается в том, чтобы найти способ кэширования открытого делегата (так что затраты на его производство начисляются только один раз) и вызывать его с помощью другого метода, который предоставляет неявный параметр "this" для делегата.

Усложняющим фактором является то, что я не знаю сигнатуры метода, который делегат будет представлять во время компиляции, кроме как через общий параметр в коде. Кроме того, я хочу избежать отражения (например, Invoke() и DynamicInvoke()), поскольку они не лучше с точки зрения производительности.

static TDel CreateOpenDelegate<TDel>( MethodInfo mi )
{
    // creates and returns an open delegate for a delegate of signature TDel
    // that will invoke some method as described by MethodInfo {mi}
    return (TDel)(object)Delegate.CreateDelegate( typeof(TDel), mi );
}

// simplification of some other code...
// Note that Action<T> is a sample usage, the actual delegate signature and
// invocation parameters vary, and are defined by the consumers of my code
private Action<T> myAction = CreateOpenDelegate<Action<U,T>>( someMethodInfo );
myAction( this, default(T) ); // can't do this since {this} is a hidden parameter...

Я уже прочитал статью Джона Скита о Сделать Reflection Fly и Изучение делегатов, к сожалению, поскольку я не знаю подпись делегата в заранее, я не вижу способа адаптировать описанный там подход.

Любая помощь будет оценена.

Теги:
generics
delegates
performance
reflection

2 ответа

2
Лучший ответ

Если я правильно понимаю ваши требования, вы, вероятно, можете использовать деревья выражений для этого - у меня есть сообщение, исследующее тему здесь *. Вот упрощенная версия:

public static D GetMethodAccessor<D>(MethodInfo mi) where D : class
{
    Type[] args = typeof(D).GetGenericArguments();
    if (args.Length == 0)
        throw new ArgumentException("Type argument D must be generic.");

    Type instanceType = args[0];

    // If return type is not null, use one less arg
    bool isAction = mi.ReturnType == typeof(void);
    int callArgCount = args.Length - (isAction ? 1 : 2);
    Type[] argTypes = args.Skip(1).Take(callArgCount).ToArray();

    var param = Expression.Parameter(instanceType, "obj");
    var arguments = argTypes.Select((t, i) => Expression.Parameter(t, "p" + i))
                            .ToArray();
    var invoke = Expression.Call(param, mi, arguments);
    var lambda = Expression.Lambda<D>(invoke,
                     Enumerable.Repeat(param, 1).Concat(arguments));

    Debug.WriteLine(lambda.Body);
    return lambda.Compile();
}

Все, что сказал, я не уверен, как дополнительная обработка аргументов и компиляция выражения сравниваются с вашим методом.

Что касается предоставления неявного 'this', можно использовать методы расширения использования?

private static Action<U,T> myAction = GetMethodAccessor<Action<U,T>>(myMethod);
public static void MyAction<U,T>(this U u, T t)
{
    myAction(u, t);
}

* Обратите внимание, что кеш-словарь на основе строк, который я использую в сообщении, ужасно неэффективен - вам нужно кэшировать делегат для частного экземпляра, например, в вашем примере.

0

Вы пытаетесь преобразовать делегат или MethodInfo в закрытый делегат?

Если вы пытаетесь преобразовать делегат в закрытый делегат, как насчет currying, вроде этого?

static Action<T2> Curry<T1, T2>(Action<T1, T2> del, T1 obj) { return p => del(obj, p); }
  • 0
    К сожалению, я заранее не знаю сигнатуру метода, поэтому не могу явно указать параметры карри. Действие <> может быть любым произвольным делегатом, определенным потребителем моего кода.
  • 0
    Если да, то к какому типу делегата вы хотите обратиться? Или у вас будет два общих параметра>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню