У меня есть интерфейс:
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
Теренс, мне нужна дополнительная информация о типах 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
}