Brent Arias
Brent Arias

Reputation: 30165

Convert Generic Method Parameter to Specific Type

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

Answers (1)

Andromedary
Andromedary

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

Related Questions