Динамическое внедрение интерфейса в .NET 4.0 (С#)
С новыми динамическими возможностями в .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
Насколько мне известно, невозможно без ручного вмешательства писать или генерировать код, который пересылает члены интерфейса к обернутому экземпляру. Если вы хотите получить поддержку Microsoft для такого рода вещей, вам может потребоваться принять участие в голосовании https://connect.microsoft.com/VisualStudio/feedback/details/526307/add-automatic-generation-of-interface-implementation-via-implementing-member
.
Ответ 2
Для этого была создана инфраструктура opensource 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);
Ответ 3
Я думаю, что написал библиотеку, которая делает то, что вы хотите... Она называется DynamicWrapper (на CodePlex), и она автоматически переносит класс, чтобы он реализовал интерфейс. Это то, что вы хотите?
Ответ 4
Явное кастинг, as
и is
завершаются сбоем из-за сопоставления типов с вашим базовым классом прокси, но неявное преобразование может вызвать DynamicObject.TryConvert, так что вы можете затем вернуть внутренний объект вместо динамического объекта.
- Документация TryConvert MSDN
В то время как приведенный ниже код работает, это не делегирование интерфейса как таковое, а только воздействие внутреннего состояния. Похоже, вы можете искать что-то вроде шаблона перехвата, такого как Brian 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;
}
}
Ответ 5
Дополняя ответ от @jbtule, я создал свой CustomActivator, который может создавать динамический объект во время выполнения и делать его реализующим желаемый интерфейс. Я также использую Интерфейс Impromptu-Interface для этого.
Вызов прост:
CustomActivator.CreateInstance<MyInterface>();
Я положил его на github.