gpt4 book ai didi

c# - 表达式中的方差 >

转载 作者:太空狗 更新时间:2023-10-29 22:33:30 27 4
gpt4 key购买 nike

这次只是一个快速而简短的。 Func<T,TResult> is contravariant (编辑:类型参数 T 是)。现在,我不使用 Func<T,TResult> , 而不是 Expression<Func<T,TResult>> ,似乎走到了死胡同。 更新 - 完整代码示例:

public interface IColoredObject
{
string Color { get; }
}

public class Item : IColoredObject
{
public string Color { get; set; }

public double Price { get; set; }
}

public partial class MainWindow : Window
{
private IList<Item> _items;

public IList<Item> Items
{
get
{
if (_items == null)
{
_items = new List<Item>();
_items.Add(new Item() { Color = "black" });
_items.Add(new Item() { Color = "blue" });
_items.Add(new Item() { Color = "red" });
}
return _items;
}
}

public MainWindow()
{
InitializeComponent();
Expression<Func<IColoredObject, bool>> filter = x => x.Color == "black";
Item i = Get(filter);
}

public Item Get(Expression<Func<Item, bool>> filter)
{
return Items.AsQueryable().Where(filter).FirstOrDefault();
}
}

调用是使用 Expression<Func<IColoredObject, bool>> 进行的作为论据并且应该,如果我没有误解逆变,工作,因为IColoredObject Item 的派生程度较低.

我得到的是一个转换异常,类似

无法转换

System.Linq.Expressions.Expression`1[System.Func`2[MyNs.IColoredObject,System.Boolean]]

System.Linq.Expressions.Expression`1[System.Func`2[MyNs.Item,System.Boolean]]

有什么方法可以解决这个问题并使其正常工作吗?

编辑:

由于我所说的有些不准确,这里有更多背景知识。代码示例已更新。此外,我检查了 MSDN 关于 Func<T, TRes> 的内容。 :

public Item GetFunc(Func<Item, bool> filter)
{
return Items.AsQueryable().Where(filter).FirstOrDefault();
}

如 MS 所示,这可以与逆变类型参数一起使用,如下所列:

 Func<IColoredObject, bool> filterFunc = x => x.Color == "black";
GetFunc(filterFunc);

这又让我想知道为什么这适用于 Func<T, TRes>但不适用于 Expression<Func<T, TRes>> ...

终于……

选中的答案之所以被选中,是因为这是我最终所做的。正如我在下面评论的某处所说,Get -方法利用NHibernate 来获取数据。但显然 NHibernate 具有通过接口(interface)接受查询并自动选择实现该接口(interface)的类型的功能。这并不能解决问题本身,但正如您在下面看到的那样,没有真正的解决方案,因为这里遇到的是预期的行为。

最佳答案

Expression<TDelegate>是一个类,因此它不能为通用参数设置方差。 Delegate之间也有很大区别和 Expression<Delegate> .虽然你可以通过 Item对象进入 Func<IColoredObject, bool>因此可以转换 Func<IColoredObject, bool>进入Func<Item, bool> , Expression<Func<Item, bool>>就像取Item的方法代码一样并返回 bool 值。您可以分析和更改此代码添加 Item特定的方法和属性,显然这对于​​使用 IColoredObject 的代码是不可能的.

可能会更改 IColoredObject 的所有条目Expression<Func<IColoredObject, bool>> 中的参数进入Item使用 ExpressionVisitor 的对象。下面是一个在简单情况下执行此类转换的访问者(即没有显式接口(interface)实现)。可能有更简单的解决方案来解决您的问题,但如果不了解更多详细信息,很难找到它。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

interface IGizmo
{
bool Frobnicate();
}

class Gizmo : IGizmo
{
public bool Frobnicate()
{
Console.WriteLine("Gizmo was frobnicated!");

return true;
}
}

public sealed class DelegateConversionVisitor : ExpressionVisitor
{
IDictionary<ParameterExpression, ParameterExpression> parametersMap;

public static Expression<Func<T2, TResult>> Convert<T1, T2, TResult>(Expression<Func<T1, TResult>> expr)
{
var parametersMap = expr.Parameters
.Where(pe => pe.Type == typeof(T1))
.ToDictionary(pe => pe, pe => Expression.Parameter(typeof(T2)));

var visitor = new DelegateConversionVisitor(parametersMap);
var newBody = visitor.Visit(expr.Body);

var parameters = expr.Parameters.Select(visitor.MapParameter);

return Expression.Lambda<Func<T2, TResult>>(newBody, parameters);
}

public DelegateConversionVisitor(IDictionary<ParameterExpression, ParameterExpression> parametersMap)
{
this.parametersMap = parametersMap;
}

protected override Expression VisitParameter(ParameterExpression node)
{
return base.VisitParameter(this.MapParameter(node));
}

private ParameterExpression MapParameter(ParameterExpression source)
{
var target = source;
this.parametersMap.TryGetValue(source, out target);

return target;
}
}

class Program
{
static void Main()
{
Expression<Func<IGizmo, bool>> expr = g => g.Frobnicate();

var e2 = DelegateConversionVisitor.Convert<IGizmo, Gizmo, bool>(expr);

var gizmo = new Gizmo();
e2.Compile()(gizmo);
}
}

关于c# - 表达式中的方差 <Func<T,bool>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11452614/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com