6

Just a quickie before the weekend rolls in...

I have a Method with the following signature, that I need to invoke:

public interface IObjectProvider<T>
{
    T Get(Predicate<T> condition);
}

This will provide me with a T from whatever kind of source, that meets the predicate criteria.

Now, this has to be called from a context where all I have is the following:

//the actual predicate that's going to be evaluated
var predicate = predicateProperty.GetValue(invocation.InvocationTarget, null);

//The type that should go into the call as type param
Type relationTargetType = relationDefinition.RelatedType;

As you might guess, the compiler won't let me use the predicate variable as parameter. What I need to do is convert this object into a Predicate, but Generic type params must be compile-time-constant, so this won't work.

I've started messing around with this, but no success so far:

Type genericPredicateType = typeof(Predicate<>);
Type specificPredicateType= genericPredicateType.MakeGenericType(relationTargetType);
Convert.ChangeType(predicate, specificPredicateType)

How on earth can I mash this up?

EDIT: I thought this was a rather use-case-agnostic question, but obviously I was wrong. So, since there is such a fuss as to what I do, what I have and why and whatnot, here's a lot more background info. I am trying to resolve relations between objects in a Proxy (Castle Dynamic Proxy). The following Snippet should explain the kind of relation I want to depict:

public class Order
{
    public virtual int Id { get; set; } // OR-Mapped
    public virtual DateTime OrderDate { get; set; } // OR-Mapped

    [RelatedObject(typeof(Address), "DeliveryAddressPredicate")]
    public virtual Address DeliveryAddress { get; set; }

    public Predicate<Address> DeliveryAddressPredicate
    {
        get { return new Predicate<Address>(a => OrderDate >= a.ValidFrom && OrderDate <= a.ValidTo); }
    }
}

public class Address
{
    public virtual DateTime ValidFrom { get; set; } // OR-Mapped
    public virtual DateTime ValidTo { get; set; } // OR-Mapped

    //Not OR-Mapped
    [RelatedList(typeof(Order), "OrdersPredicate")]
    public virtual IList<Order> Orders { get; set; }

    public Predicate<Order> OrdersPredicate
    {
        get { return new Predicate<Order>(o => o.OrderDate >= ValidFrom && o.OrderDate <= ValidTo); }
    }

To sum it up, this is supposed to become a Fuzzy OR-Mapping, meant to extend NHibernate in a project or two.

How did I mean to get this to work? The address is proxied, and when a call to a property with one of my CustomAttributes is made, i use DynamicProxy's IInterceptor interface to resolve the relation. The main problem is that this resolving has to happen in the IInterceptor.Intercept() Method which has only one Param (see here), and I have no generic type param available. So, in the end it all boils down to a simple .Net question again: I have a Type stored in a variable and a Method that has to be called with a parameter generic of the aforesaid type...

Sorry for any mistakes made (like calling var a Type - man that was a rough one), it's been quite a day ;-)

Sebastian Edelmeier
  • 4,095
  • 3
  • 39
  • 60

3 Answers3

8

You have some IObjectProvider<T>. If T is a type know at compile-time, you can just use a cast. For example, if T was Foo:

IObjectProvider<Foo> provider = …;
var predicate = (Predicate<Foo>)predicateProperty.GetValue(
    invocation.InvocationTarget, null);
Foo item = provider.Get(predicate);

EDIT: It seems you don't know T at compile time. This means you have two options:

  1. Use dynamic:

    object provider = …
    object predicate = predicateProperty.GetValue(
        invocation.InvocationTarget, null);
    object item = ((dynamic)provider).Get((dynamic)predicate);
    
  2. Use reflection:

    object provider = …;
    object predicate = predicateProperty.GetValue(
        invocation.InvocationTarget, null);
    var getMethod = provider.GetType().GetMethod("Get");
    object item = getMethod.Invoke(provider, new[] { predicate });
    
svick
  • 236,525
  • 50
  • 385
  • 514
  • 1
    Please re-check the Original Post. I have no Compile-Time support here. – Sebastian Edelmeier Mar 24 '12 at 02:21
  • 1
    Thanks, Svick, this is the best answer I got, and I'm using the dynamic solution right now. – Sebastian Edelmeier Mar 26 '12 at 08:12
  • As mentioned above, I tried to get it to work using your dynamic sample, but I keep on running into ´CS1502 : The best overloaded method match for ... has some invalid arguments.´ Obviously the dynamic Type is not correctly resolved as being the static one defined in the ´Provider´-class. Any ideas how this can Occur? – Sebastian Edelmeier Mar 26 '12 at 10:17
  • You mean you get a compile error? Do you have some more details on the error? Which line is causing it? Is there some other message (something like “Argument 1: cannot convert from …”)? – svick Mar 26 '12 at 10:22
  • object item = ((dynamic)provider).Get(predicate); – Sebastian Edelmeier Mar 26 '12 at 11:47
  • It occurs at runtime, not compile time. I guess that's what happens when you use dynamic... – Sebastian Edelmeier Mar 26 '12 at 11:49
  • You're right, the code doesn't work. But `((dynamic)provider).Get((dynamic)predicate)` does. – svick Mar 26 '12 at 12:07
1

This question shows a lot of confusion about types, var etc.

This is a meaningless sentence

It is of type var and GetValue turned it into an object.

I think you are saying

I have some code that needs a Predicate<T>

You have some code (that you don't show us) that returns an Object. And want somehow to coerce that return value into a Predicate<T>. If the returned object is a Predicate<T> then simply go (Predicate<T>)retobj - and you are done. If it's not a type that can be cast to Predicate<T> then no amount of jiggling will make it into a Predicate<T>.

svick
  • 236,525
  • 50
  • 385
  • 514
pm100
  • 48,078
  • 23
  • 82
  • 145
  • 2
    The OP did show us that code: `predicateProperty.GetValue()`. Also, casting to `Predicate` could work only inside a generic type or method with type parameter called `T`. Otherwise, you need to specify some concrete type, e.g. `(Predicate)retobj`. – svick Mar 23 '12 at 16:21
  • Also, you're slightly wrong that you can't make some other type into a `Predicate`. For example, you can't cast `Func` to `Predicate`, but you can use “jiggling” in the form of an constructor to do it: `new Predicate(func)`. – svick Mar 23 '12 at 16:25
  • Thanks, svick, for getting this straight. I will update the original Post to clarify the problem. – Sebastian Edelmeier Mar 24 '12 at 01:42
  • pm100, you actually got it boiled down to it's essence. I cannot cast the object to Predicate (although it is one), since I have no Generic Type Parameter T. All I have is a variable that contains the type. – Sebastian Edelmeier Mar 24 '12 at 02:26
-1

I do this way

public T CastToType<T>(object objType, T type) where T : class
    {
        var cast = objType as T;

        if(cast == null)
            throw new InvalidCastException();

        return cast;
    }

And like this

var test = CastToType(objType, new ArrayList());

test will be have ArrayList type