I have an interface:
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
}
}
Then, I have a bunch of different classes which all implement RequiresAuthorization, and correspondingly, an Authorizer<T>
for each of them (each business object in my domain requires different logic to execute once the record has been authorized).
I'm also using a UnityContainer, in which I register various Authorizer<T>
's. I then have some code as follows to find the right record out of the database and authorize it:
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);
}
Basically, I'm using the Id on the object to retrieve it out of the database. In the background NHibernate takes care of figuring out what type of RequiresAuthorization it is. I then want to find the right Authorizer for it (I don't know at compile time what implementation of Authorizer<T>
I need, so I've got a little bit of reflection to get the fully qualified type). To accomplish this, I use the non-generic overload of UnityContainer's Resolve method to look up the correct authorizer from configuration.
Finally, I want to call Authorize on the authorizer, passing through the object I've gotten back from NHibernate.
Now, for the problem:
In Beta2 of VS2010 the above code works perfectly. On RC and RTM, as soon as I make the Authorize() call, I get a RuntimeBinderException saying "The best overloaded method match for 'Foo.Authorizer<Bar>.Authorize(Bar)'
has some invalid arguments". When I inspect the authorizer in the debugger, it's the correct type. When I call GetType().GetMethods() on it, I can see the Authorize method which takes a Bar. If I do GetType() on dbItem it is a Bar.
Because this worked in Beta2 and not in RC, I assumed it was a regression (it seems like it should work) and I delayed sorting it out until after I'd had a chance to test it on the RTM version of C# 4.0. Now I've done that and the problem still persists. Does anybody have any suggestions to make this work?
Thanks
Terence
Terence, I'd need more information here about the types in play and their definitions to know what the problem really is, but this error is basically telling you that it could not convert dbItem
to Bar
. There are two possibilities:
1) RetrieveRequiresAuthorizationById()
returns dynamic
, and therefore the compile-time type of dbItem
is inferred to be dynamic
. If this is the case, then the runtime binder will select a type for dbItem
at runtime that is essentially the best accessible type if can find. This type is not convertible to Bar
given the accessibility. For example, it could be that dbItem
's runtime type is some inaccessible type with a direct base class of object
, and obviously object
is not convertible to Bar
.
2) RetrieveRequiresAuthorizationById()
returns some static type. In that case, the static type is not convertible to Bar
at runtime.
My guess is that (2) is the case, and that the type of dbItem
is RequiresAuthorization
. Which I am also guessing is an interface. And that's not going to be convertible to any class type.
If I'm right, what you want to do is make dbItem
dynamic. If you do, then the runtime binder will select the appropriate type for dbItem
, which is presumably the whole reason you want to do this.
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With