将动态转换为通用类型

6

周末到来之前,简单说一下...

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

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”变量作为参数。我需要将此对象转换为Predicate,但泛型参数必须是编译时常量,因此这样做行不通。我已经开始尝试了一些方法,但目前还没有成功。
Type genericPredicateType = typeof(Predicate<>);
Type specificPredicateType= genericPredicateType.MakeGenericType(relationTargetType);
Convert.ChangeType(predicate, specificPredicateType)

我该如何混合这个东西?
编辑:我认为这是一个相当通用的问题,但显然我错了。既然有这么多关注我在做什么、我拥有什么以及为什么等等问题,那么在此提供更多背景信息。我正在尝试解决代理对象(Castle Dynamic Proxy)中的对象关系。以下代码片段应该能够解释我想要描述的关系类型:
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映射,旨在扩展NHibernate中的一个或两个项目。
我是如何让它工作的?地址被代理,当使用我的CustomAttributes之一的属性进行调用时,我使用DynamicProxy的IInterceptor接口来解决关系。主要问题是这个解决必须发生在只有一个参数(see here)的IInterceptor.Intercept()方法中,而我没有泛型类型参数可用。因此,最终所有问题都归结为一个简单的.Net问题:我在一个变量中存储了一个Type,并且必须使用一个参数通用于上述类型的Method进行调用...
对于任何错误(例如将var称为Type-这真是一次艰难的经历),我表示歉意,今天过得很辛苦;-)

predicateProperty.GetValue 的返回类型是什么? - Chris Shain
PropertyInfo.GetValue --> Object :-(属性信息.获取值 --> 对象 :-( - Sebastian Edelmeier
3
顺便提一下,"predicate" 不是 "var" 类型;"var" 并不是一种类型! - Alexander R
1
@Eric,嗯,它可以谨慎使用。使用MakeGenericType并不是“非常恶劣”的代码,但它确实是泛型和反射的交汇点。 - Kirk Woll
@KirkWoll - 我同意。主要是对OP表示同情。试图弄清楚如何处理所有这些问题会让你的大脑变得混乱不堪。 - Eric Andres
显示剩余4条评论
3个回答

8

您有一些 IObjectProvider<T>。如果 T 是在编译时已知的类型,您可以直接使用强制转换。例如,如果 TFoo

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

编辑:看来您无法在编译时知道T。这意味着您有两个选择:

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

1
请重新检查原始帖子。我这里没有编译时支持。 - Sebastian Edelmeier
1
谢谢,Svick,这是我收到的最佳答案,我正在使用动态解决方案。 - Sebastian Edelmeier
如上所述,我尝试使用您的动态示例使其正常工作,但是我一直遇到“CS1502:最佳重载方法匹配...具有一些无效参数。”显然,动态类型未正确解析为“Provider”类中定义的静态类型。有什么想法吗? - Sebastian Edelmeier
你的意思是编译出错了吗?你有关于错误的更多细节吗?哪一行引起了错误?是否有其他消息(例如“参数1:无法转换为…”)? - svick
它在运行时发生,而不是在编译时。我猜这就是当你使用动态时会发生的情况... - Sebastian Edelmeier
显示剩余2条评论

1

这个问题显示了很多混淆类型、var等的困惑。

这是一个毫无意义的句子。

它是var类型,而 GetValue 把它转换成了对象。

我想你是想说

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

你有一些代码(但我们看不到),它返回一个 Object。并希望以某种方式将返回值强制转换为 Predicate<T>。如果返回的对象是 Predicate<T>,那么只需执行 (Predicate<T>)retobj 即可完成操作。如果它不是可以转换为 Predicate<T> 的类型,则无论如何都不能将其转换为 Predicate<T>


2
OP已经展示了这段代码:predicateProperty.GetValue()。此外,将其转换为Predicate<T>只能在具有名为T的类型参数的泛型类型或方法内起作用。否则,您需要指定一些具体的类型,例如(Predicate<string>)retobj - svick
另外,你稍微有些错误,认为你不能将其他类型转换为 Predicate<T>。例如,你不能将 Func<string, bool> 强制转换为 Predicate<T>,但是你可以使用“摇晃”的形式来构造它:new Predicate<string>(func) - svick
感谢您,svick,解决了这个问题。我会更新原帖以澄清问题。 - Sebastian Edelmeier
pm100,你把它精简到了本质。尽管我有一个 Predicate<T> 对象(这是一个),但我不能将其转换为对象,因为我没有泛型类型参数T。我只有一个包含该类型的变量。 - Sebastian Edelmeier

-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类型


2
不需要第二个参数。 - Harry13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接