动态转换为泛型类型

时间:2012-03-23 15:45:09

标签: c# generics dynamic type-conversion castle-dynamicproxy

在周末开始之​​前快点......

我有一个带有以下签名的方法,我需要调用:

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

这将为我提供符合谓词标准的任何来源的T

现在,必须从我所拥有的上下文中调用它:

//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;

正如您可能猜到的,编译器不允许我使用predicate变量作为参数。我需要做的是将此对象转换为谓词,但通用类型参数必须是编译时常量,所以这不起作用。

我已经开始搞乱这个,但到目前为止没有成功:

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

我怎么能把它混搭?

编辑:我认为这是一个与用例无关的问题,但显然我错了。所以,既然对我所做的事情,我拥有的以及为什么以及诸如此类的事情有这么大惊小怪,这里有更多的背景信息。我试图解决代理(城堡动态代理)中的对象之间的关系。以下代码片段应该解释我想要描述的那种关系:

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); }
    }

总结一下,这应该是一个模糊的OR-Mapping,意味着在一两个项目中扩展NHibernate。

我是如何让这个工作的?代理地址,当使用我的CustomAttributes之一调用属性时,我使用DynamicProxy的IInterceptor接口来解析关系。主要问题是这个解析必须在IInterceptor.Intercept()方法中发生,它只有一个Param(see here),并且我没有可用的泛型类型参数。所以,最后这一切归结为一个简单的.Net问题:我有一个Type存储在一个变量中,Method必须用上述类型的泛型参数调用。 ..

对于发生的任何错误(比如致电var一个Type - 一个粗略的人)抱歉,这已经过了一天; - )

3 个答案:

答案 0 :(得分:8)

你有一些IObjectProvider<T>。如果T是编译时知道的类型,则可以使用强制转换。例如,如果TFoo

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

编辑:您似乎在编译时不知道T。这意味着您有两种选择:

  1. 使用dynamic

    object provider = …
    object predicate = predicateProperty.GetValue(
        invocation.InvocationTarget, null);
    object item = ((dynamic)provider).Get((dynamic)predicate);
    
  2. 使用反射:

    object provider = …;
    object predicate = predicateProperty.GetValue(
        invocation.InvocationTarget, null);
    var getMethod = provider.GetType().GetMethod("Get");
    object item = getMethod.Invoke(provider, new[] { predicate });
    

答案 1 :(得分:1)

这个问题显示了很多关于类型,var等的混淆。

这是一个毫无意义的句子

  

类型为var,GetValue将其转换为对象。

我想你在说

  

我有一些代码需要Predicate<T>

您有一些返回Object的代码(您没有向我们展示)。并希望以某种方式将该返回值强制转换为Predicate<T>。如果返回的对象是Predicate<T>,那么只需转到(Predicate<T>)retobj - 就完成了。如果它不是可以转换为Predicate<T>的类型,那么任何数量的摇晃都不会使其成为Predicate<T>

答案 2 :(得分:-1)

我这样做

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

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

        return cast;
    }

就像这样

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

测试将具有ArrayList类型