Декоратор общего назначения, корректно ожидающий ожидаемого типа, полученного из Reflection.C#

Место общения программистов C#
Ответить
Anonymous
 Декоратор общего назначения, корректно ожидающий ожидаемого типа, полученного из Reflection.

Сообщение Anonymous »

Преамбула: я искал, как лучше всего реализовать на C# декоратор общего назначения, который справляется с асинхронными методами. В большинстве примеров используется DispatcherProxy, который предлагает только синхронный вызов. Если NET не улучшит это и не добавит поддержку асинхронности, которая в настоящее время закрыта, нам останется вызывать это так же, как обычный конкретный декоратор. Проблема, кажется, заключается в том, что из-за решения сделать awaitables шаблоном не существует чистого способа обнаружить это обстоятельство и правильно написать код, но я надеюсь, что кто-то более знаком с глубинами Отражение может пролить свет.
Сначала конкретный простой пример:

Код: Выделить всё

interface IMyWork
{
Task DoStuff();
}

class MyWork : IMyWork
{
public async Task DoStuff() { await Something(); }
}

// A decorator like any other
class MyDecoratedWork : IMyWork
{
private readonly MyWork _real;

public Task DoStuff()
{
using var scope = Decorate();
await _real.Something();
// Disposal is in the same context as Decorate was - things like AsyncLocal are restored
}

private IDisposable Decorate() { /* return some scoped decoration /* }
}
Это легко, если вы хотите написать декораторы вручную, но если вам нужно написать их много, становится привлекательно иметь декоратор общего назначения. Примеры обычно выглядят следующим образом:

Код: Выделить всё

class DispatchProxyScopedDecorator : DispatchProxy
{
private TDecorated? _decorated;
private IScopeProvider? _scopeProvider;

private void SetParameters(TDecorated decorated, IScopeProviderscopeProvider)
{
_decorated = decorated;
_scopeProvider = scopeProvider;
}

protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
// The important bit
}

public static TDecorated Create(TDecorated decorated, IScopeProvider scopeProvider)
{
object created = Create()!;
((DispatchProxyScopedDecorator)created).SetParameters(decorated, scopeProvider);

return (TDecorated)created;
}
}
Синхронный случай прост:

Код: Выделить всё

protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
using var scope = _scopeProvider.Decorate();
return targetMethod?.Invoke(_decorated, args);
}
но Invoke — это синхронный метод, что означает, что для правильного оформления вызова метода, который возвращает ожидаемый объект, тип возвращаемого значения должен быть перехвачен новым ожидаемым объектом.
Похоже, что единственным требованием является реализация метода GetAwaiter (такие вещи, как AsyncStateMachineAttribute, не обязательно применяются).

Код: Выделить всё

var scope = _scopeProvider.Decorate();

var result = targetMethod.Invoke(_decorated, args);

if (result is null)
{
return null;
}

// This isn't complete - also needs to hunt through assemblies for extension methods!
var awaiterMethod = result.GetType().GetMethod("GetAwaiter");
Если это значение не равно нулю, у меня есть ожидаемый объект. Мой идеал с точки зрения простого в обслуживании кода — просто поместить его в асинхронный метод и позволить компилятору выполнить тяжелую работу:

Код: Выделить всё

async Task InterceptAsync(??? awaitable, MyScope scope)
{
try
{
await awaitable;
}
finally
{
scope.Dispose();
}
}

if (awaiterMethod is not null)
{
return InterceptAsync(result, scope);
}
К сожалению, это не компилируется по очевидным причинам: поскольку ожидаемый объект не является единственным типом, я не могу предоставить ??? ничего, что мог бы принять компилятор ( кроме, возможно, динамического, но это устарело).
Как и у любого декоратора, есть очевидные недостатки (производительность, потенциальное изменение типа возвращаемого значения), но осуществимо ли это вообще? Мне не хватает какого-то другого подхода? Я сразу подумал, что если исходный код не возвращает Task, приведенное выше нарушит сигнатуру ожидаемого метода. Но означает ли это, что для каждого отдельного ожидаемого объекта требуется своя собственная реализация?
Мысли оценены по достоинству.

Подробнее здесь: https://stackoverflow.com/questions/791 ... ained-from
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»