Reputation: 30165
Given a generic method Get<T>
which takes the following parameter...
Expression<Func<T,bool>> foo
Within that method body I want to test if 'T' is typeof(Stuff) and if yes, then cast it:
Expression<Func<Stuff,bool>> boo = (???) foo;
The first reaction I expect is "No need to cast it, it is already of type Stuff
if that was passed in." But I have found that is not true where method dispatching is concerned!!
So yes I need to test and cast but don't know how.
Below is the context of why and where this is necessary.
I have code like this:
public class Stuff {
public int Alpha;
}
interface ISomething {
List<T> Get<T>(Expression<Func<T,bool>> lambda);
}
public class Something : ISomething {
List<T> Get<T>(Expression<Func<T,bool>> expr){
//...
//Makes non-recursive call to non-generic 'Get' method.
//Works as expected.
Get((Stuff x) => x.Alpha > 10);
//UH-OH! makes recursive call to Get<T> even when T is typeof(Stuff)!
//This is where casting is needed!
Get(expr);
//...
}
List<Stuff> Get(Expression<Func<Stuff,bool>> expr){
//...
}
}
My intention is to have the generic method Get<T>
call the non-generic Get
if the expr
LambdaExpression
specifically takes a parameter of type Stuff
. But that is not what happens in the above code.
If I run this code...
ISomething foo = new Something();
var result = foo.Get((Stuff x) => x.Alpha < 20);
...the function called is Get<T>
. This is not surprising, even though the non-generic Get
is a better match, because Get<T>
is the only available match within the ISomething interface. So for this is ok.
But once the Get<T>
method executes, I want the non-generic Get
to be invoked with the same argument named expr
. Given the behavior I'm observing, it looks as though I can only get what I want if I cast the Expression<Func<T,bool>>
to Expression<Func<Stuff,bool>>
. This also assumes I have an test, like is
or as
, to confirm it is castable.
How is the type-test done, and how is the cast done?
Is there another way to coerce the more specific and non-generic Get
method to be called? Please assume the caller must work through the ISomething
interface only.
Granted, it would be even more ideal if the non-generic Get
was called immediately without going through Get<T>
at all. But if I'm forced to work through the ISomething
interface, I don't think that is possible.
FYI, if a way can be found to make this work - it would then provide functionality that is somewhat similar to "traits - the else-then-if" in C++.
Upvotes: 2
Views: 1014
Reputation: 3548
How about something like this:
public List<T> Get<T>(Expression<Func<T,bool>> expr){
var expr2 = expr as Expression<Func<Stuff, bool>>;
if (expr2 != null){
return Get(expr2) as List<T>;
}
//...
}
This code makes ReSharper freak out, but it appears to work :)
A better option, if possible, would be to add a non-generic overload to ISomething.
Upvotes: 3