Динамическая реализация интерфейса в .NET 4.0 (C #) - PullRequest
43 голосов
/ 04 июня 2010

С новыми динамическими возможностями в .NET 4.0 кажется, что должна быть возможность динамически реализовать интерфейс, например, Дано:

public interface IFoo 
{
    string Bar(int baz);
}

public class Foo : IFoo
{
    public string Bar(int baz) { return baz.ToString(); }
}

public class Proxy : IDynamicMetaObjectProvider
{
    private readonly object target;

    public Proxy(object target) { this.target = target; }

    // something clever goes here
}

Тогда я надеюсь, что есть какой-то способ написать:

dynamic proxy = new Proxy(new Foo());
IFoo fooProxy = (IFoo)proxy; // because the target object implements it
string bar = fooProxy.Bar(123); // delegates through to the target implementation

Но пока я не уверен, что заменить // something clever goes here на.

Итак, мои вопросы:

  1. Возможно ли это на самом деле сделать с динамическим временем выполнения? Похоже, что динамически реализовать такие вещи, как методы и свойства, довольно легко, но я не нашел никакой документации о динамически реализуемых интерфейсах и преобразованиях к ним.

  2. Предполагая, что это возможно, насколько сложно это будет? (Вы можете предположить, что я приличный программист с большим опытом таких вещей, как рефлексия, но новичок в динамической среде.)

  3. Есть ли какие-либо ресурсы, которые помогли бы указать мне правильное направление для реализации чего-то подобного? Или даже образцы, в которых подобные вещи уже сделаны, и я могу использовать их в качестве отправной точки?

Ответы [ 5 ]

41 голосов
/ 28 февраля 2011

Платформа с открытым исходным кодом Impromptu-Interface была разработана для этого.Он генерирует кэшированный облегченный прокси со статическим интерфейсом и использует dlr для пересылки вызова исходному объекту.

using ImpromptuInterface;

public interface ISimpeleClassProps
{
    string Prop1 { get;  }

    long Prop2 { get; }

    Guid Prop3 { get; }
}

-

dynamic tOriginal= new ExpandoObject();
tOriginal.Prop1 = "Test";
tOriginal.Prop2 = 42L;
tOriginal.Prop3 = Guid.NewGuid();

ISimpeleClassProps tActsLike = Impromptu.ActLike(tOriginal);
13 голосов
/ 04 июня 2010

Насколько я знаю, без ручного вмешательства невозможно написать или сгенерировать код, который перенаправляет элементы интерфейса в упакованный экземпляр. Если вы хотите, чтобы Microsoft предоставила поддержку для такого рода вещей, вы можете рассмотреть возможность голосования по номеру https://connect.microsoft.com/VisualStudio/feedback/details/526307/add-automatic-generation-of-interface-implementation-via-implementing-member .

7 голосов
/ 04 июня 2010

Я думаю, что написал библиотеку, которая делает то, что вы хотите ... Она называется DynamicWrapper (в CodePlex) и автоматически оборачивает класс, чтобы реализовать интерфейс. Это то, что вы хотите?

3 голосов
/ 04 июня 2010

Явное приведение, as и is завершились неудачно из-за сравнения типов с базовым классом прокси, но неявное приведение может вызвать DynamicObject.TryConvert, так что вы можете затем вернуть внутренний объект вместо динамического объекта .
- Документация TryConvert MSDN

Хотя приведенный ниже код работает, это не делегирование интерфейса как таковое, а только раскрытие внутреннего состояния. Похоже, вы ищете что-то вроде шаблона перехвата, такого как DynamicWrapper Брайана.

dynamic wrapper = new Proxy(new Foo());
IFoo foo = wrapper;
foo.Bar();

class Proxy : DynamicObject
{
    ...

    public override bool TryConvert(ConvertBinder binder, out object result)
    {
        Type bindingType = binder.Type;
        if (bindingType.IsInstanceOfType(target))
        {
            result = target;
            return true;
        }
        result = null;
        return false;

    }

}
2 голосов
/ 17 мая 2015

В дополнение к ответу от @jbtule Я создал свой CustomActivator, который способен создавать динамический объект во время выполнения и заставлять его реализовать желаемый интерфейс. Для этого я также использую инфраструктуру Impromptu-Interface .

Звонок прост:

CustomActivator.CreateInstance<MyInterface>();

Я положил его на github .

...