Статические вызовы с поздним связыванием - C # 4.0 - PullRequest
0 голосов
/ 02 сентября 2011

Моя цель - иметь возможность использовать intellisense, в то же время инструктируя компилятор генерировать код позднего связывания (т. Е. CallSites and Binder).

Скажи, что у меня

class MyDynamicDataProvider
{
   public int Data{get;set}
}

Я хочу написать:

MyDynamicDataProvider provider = new MyDynamicDataProvider();
int x = provider.Data;

Я хочу, чтобы вызов свойства Data имел позднюю привязку. Однако в настоящее время, если я не объявлю переменную provider как динамическую, компилятор будет предварительно связывать вызов. во время выполнения будет возвращено значение, сохраненное в вспомогательном поле свойства.

В то же время я хочу использовать intelllisense при кодировании, что означает, что я должен объявить провайдера, используя соответствующий тип.

Есть ли способ одновременного достижения обоих концов (используя статические объявления для intellisense, полагаясь на динамическое связывание во время выполнения)?

Редактировать 1: Можно задаться вопросом, почему бы просто не использовать геттер для выполнения любой логики, которая мне нужна. Дело в том, что я пытаюсь разработать некоторые мета-классы, которые позволили бы разработчикам просто определять классы и свойства, использовать методы получения, установки, методы и т. Д., В то время как магия происходит с помощью динамических средств. Таких типов было бы много, и я бы хотел избежать такого избыточного кода в самих классах.

Редактировать 2: Было бы неплохо, если бы я мог объявить класс с атрибутом, который сообщает компилятору о поздней привязке всех вызовов к его членам.

Ответы [ 4 ]

2 голосов
/ 02 сентября 2011

Visual Studio не может предоставить intellisense для объекта с поздней привязкой, поскольку он не знает, существует ли член на самом деле.Visual Studio может возможно предоставить это «из коробки», но это не так.Intellisense по умолчанию просто отключается на динамике.Есть два решения:

  1. Если вы знаете участника, которому хотите позвонить, почему вы вообще пытаетесь использовать позднюю привязку?
  2. Некоторые продукты, такие как Resharper предоставляет псевдоинтеллектуальный смысл, статически ища вызовы с поздней привязкой, которые были сделаны еще где.На изображении ниже это обеспечивает intellisense для Hello, потому что в другом месте есть код, который выполняет этот вызов.Это умно, но и не надежно.

Resharper

1 голос
/ 02 сентября 2011

Для этого вам лучше всего реализовать Data, чтобы он динамически делал то, что вам нужно , возможно, используя фасад.

Если мы предполагаем, что у вас каким-то образом есть MyDynamicDataProvider,он знает, что делать, когда он называется динамическим - тогда вы можете использовать статически типизированный фасад, подобный этому:

 class DataProviderFacade 
 { 
     private dynamic inner;
     public DataProviderFacade(dynamic inner)
     {
         this.inner = inner;
     }

     public int Data { get { return inner.Data; } }
 }

При этом я не могу представить, зачем вам это нужно.

0 голосов
/ 07 сентября 2011

Если вы используете ImpromptuInterface с открытым исходным кодом (через nuget), вы можете определить статические интерфейсы, а затем он будет генерировать и кэшировать динамический код привязки (места вызова и связыватели), соответствующие элементам этого интерфейса. Вы просто используете один универсальный метод расширения для объекта с именем ActLike , и он будет статически возвращать этот интерфейс и фактически вернет испущенный прокси, который реализует этот интерфейс и перенаправляет вызовы через динамическое связывание c # (поэтому он будет работать со статическим и динамические объекты, подобные).

После однократной генерации прокси затраты производительности для вызова метода составляют всего один статический вызов + один динамический вызов.

public interface IMyDynamicDataProvider
{
   int Data{get;set}
}

...

IMyDynamicDataProviderprovider = new MyDynamicDataProvider().ActLike<IMyDynamicDataProvider>();
int x = provider.Data;
0 голосов
/ 02 сентября 2011

Кажется, вы на самом деле не хотите dynamic, вы просто хотите динамически реализовать функциональность для статически определенных свойств и методов.Если это так, вы можете создать классы как абстрактные, а затем динамически реализовать их.

Существует несколько способов сделать это.Либо непосредственно используйте Reflection.Emit, либо CodeDOM для генерации классов, которые наследуются от абстрактных.Или вы можете использовать инструмент, который делает это намного проще (и обычно несколько медленнее), например Castle DynamicProxy .

...