RuntimeBinderException с динамическим в C# 4.0

У меня есть интерфейс:

public abstract class Authorizer<T> where T : RequiresAuthorization
{
    public AuthorizationStatus Authorize(T record)
    {
        // Perform authorization specific stuff
        // and then hand off to an abstract method to handle T-specific stuff
        // that should happen when authorization is successful

    }
}

Затем у меня есть набор различных классов который вся реализация RequiresAuthorization, и соответственно, Authorizer<T> для каждого из них (каждый бизнес-объект в моем домене требует, чтобы другая логика выполнилась, после того как запись была авторизована).

Я также использую UnityContainer, в котором я регистрируюсь различный Authorizer<T>. У меня затем есть некоторый код следующим образом, чтобы найти правильную запись из базы данных и авторизовать его:

void Authorize(RequiresAuthorization item)
{
    var dbItem = ChildContainer.Resolve<IAuthorizationRepository>()
                               .RetrieveRequiresAuthorizationById(item.Id);
    var authorizerType = type.GetType(String.Format("Foo.Authorizer`1[[{0}]], Foo",
                             dbItem.GetType().AssemblyQualifiedName));
    dynamic authorizer = ChildContainer.Resolve(type) as dynamic;

    authorizer.Authorize(dbItem);
}

В основном я использую идентификатор на объекте получить его из базы данных. В фоновом режиме NHibernate заботится о выяснении, какое RequiresAuthorization это. Я затем хочу найти правильный Authorizer для него (я не знаю во время компиляции что реализация Authorizer<T> Мне нужно, таким образом, у меня есть определенное отражение для получения полностью определенного типа). Для выполнения этого я использую неуниверсальную перегрузку метода Твердости UnityContainer для поиска корректного authorizer из конфигурации.

Наконец, я хочу звонить, Авторизовывают на authorizer, проходя через объект, который я возвратил от NHibernate.

Теперь, для проблемы:

В Beta2 VS2010 вышеупомянутый код работает отлично. На RC и RTM, как только я делаю Авторизовывание () вызов, я получаю RuntimeBinderException, говоря "Лучшее соответствие перегруженного метода для 'Foo.Authorizer<Bar>.Authorize(Bar)' имеет некоторые недействительные аргументы". Когда я осматриваю authorizer в отладчике, это - корректный тип. Когда я называю GetType ().GetMethods () на нем, я вижу Авторизовать метод, который берет Панель. Если я делаю GetType () на dbItem, это - Панель.

Поскольку это работало в Beta2 а не в RC, я предположил, что это была регрессия (кажется, что он должен работать), и я задержал улаживание его, пока у меня не было шанса протестировать его на версии RTM C# 4.0. Теперь я сделал это, и проблема все еще сохраняется. У кого-либо есть какие-либо предложения для создания этой работы?

Спасибо

Terence

6
задан Terence Lewis 15 April 2010 в 12:55
поделиться

1 ответ

Теренс, мне нужна дополнительная информация о типах in play и их определения, чтобы узнать, в чем проблема на самом деле, но эта ошибка в основном сообщает вам, что не удалось преобразовать dbItem в Bar . Есть две возможности:

1) RetrieveRequiresAuthorizationById () возвращает динамический , поэтому тип времени компиляции dbItem предполагается как динамический . В этом случае средство связывания времени выполнения выберет тип для dbItem во время выполнения, который, по сути, является наилучшим доступным типом, если его удастся найти. Этот тип не может быть преобразован в Бар с учетом доступности. Например, может случиться так, что тип среды выполнения dbItem - это какой-то недоступный тип с прямым базовым классом объекта , и, очевидно, объект не может быть преобразован в Бар .

2) RetrieveRequiresAuthorizationById () возвращает некоторый статический тип. В этом случае статический тип не может быть преобразован в Bar во время выполнения.

Я предполагаю, что (2) имеет место, а тип dbItem - RequiresAuthorization . Я также предполагаю, что это интерфейс. И это не будет преобразовано ни в какой класс.

Если я прав, вы хотите сделать dbItem динамическим. Если вы это сделаете, то связыватель времени выполнения выберет соответствующий тип для dbItem , что, вероятно, и является единственной причиной, по которой вы хотите это сделать.

void Authorize(RequiresAuthorization item)
{
    var dbItem = ChildContainer.Resolve<IAuthorizationRepository>()
                               .RetrieveRequiresAuthorizationById(item.Id);
    var authorizerType = type.GetType(String.Format("Foo.Authorizer`1[[{0}]], Foo",
                             dbItem.GetType().AssemblyQualifiedName));
    dynamic authorizer = ChildContainer.Resolve(type) as dynamic;

    authorizer.Authorize(dbItem as dynamic); // <<<Note "as" here
}
11
ответ дан 9 December 2019 в 22:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: