首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何将Expression<Func<T1,U>>转换为Expression<Func<T2,U>>?

如何将Expression<Func<T1,U>>转换为Expression<Func<T2,U>>?
EN

Stack Overflow用户
提问于 2019-06-19 22:36:15
回答 1查看 53关注 0票数 0

考虑下面的示例项目。给定一个Expression<Func<T, U>>表达式,我想创建一个可以为实现根接口(IBase)的任何T调用的表达式。

问题所在

下面的表达式转换器似乎可以正常工作,但当在更高级的表达式中调用时,转换后的Func会抛出InvalidOperationException。到目前为止,我还不能重现这一点。不过,看一下结果表达式,我确实看到有两个参数- tParam_0 -我认为这会以某种方式导致问题。

名称:从作用域‘System.InvalidOperationException’引用了类型为'IBase‘的'variable 't’,但未定义它‘

下面的转换方法必须以某种方式改进。敬请指教!

代码语言:javascript
复制
namespace ExpressionTest
{
    interface IBase
    {
        string Name { get; set; }
    }

    interface IFoo : IBase
    {
        string Foo { get; set; }
    }

    interface IBar : IBase
    {
        string Bar { get; set; }
    }

    class FooImpl : IFoo
    {
        public FooImpl()
        {
            Name = "Name";
            Foo = "Foo";

            var e1 = Test<IBase, string>(t => t.Name);
            var e2 = Test<IFoo, string>(t => t.Foo);
            var e3 = Test<IBar, string>(t => t.Bar);

            var e4 = Test2<IBase, string>((b, v) => Stuff(b, v));
            e4.Compile().Invoke(this, "new");

            var name = e1.Compile().Invoke(this);
            var foo = e2.Compile().Invoke(this);

            // TODO: Use "as" operator instead of cast...
            // var bar = e3.Compile().Invoke(this);
        }

        public void Stuff(IBase b, string v)
        {
            b.Name = v;
        }

        public string Name { get; set; }
        public string Foo { get; set; }

        private Expression<Func<IBase, TProperty>>
            Test<T, TProperty>(Expression<Func<T, TProperty>> expr)
            where T : IBase
        {
            var p = Expression.Parameter(typeof(IBase));
            var convert = Expression.Convert(p, typeof(T));
            var invoke = Expression.Invoke(expr, convert);
            var lambda = Expression.Lambda<Func<IBase, TProperty>>(invoke, p);
            return lambda;
        }

        private Expression<Action<IBase, TProperty>>
            Test2<T, TProperty>(Expression<Action<T, TProperty>> expr)
            where T : IBase
        {
            var p1 = expr.Parameters.Last();
            var p2 = Expression.Parameter(typeof(IBase));
            var convert = Expression.Convert(p2, typeof(T));
            var invoke = Expression.Invoke(expr, convert, p1);
            var lambda = Expression.Lambda<Action<IBase, TProperty>>(invoke, p2, p1);

            return lambda;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var foo = new FooImpl();
        }
    }
}

如果中间接口(例如IBar)没有实现,它应该只返回默认值-这在我的示例代码中没有实现。

更新

基本上,我想模仿一下:

代码语言:javascript
复制
string MyFooExpressionCompiledMethod(IBase b)
{
    if (b is IFoo foo)
    {
        return foo.Foo;
    }
    return null;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-21 03:24:06

如果不能复制您的错误,就很难说出哪里出了问题。使用LINQPad及其转储工具可以帮助查看表达式创建并对它们进行比较。

但是,将适当的条件逻辑添加到您的生成中并不困难。

对于Test

代码语言:javascript
复制
var iif = Expression.Condition(Expression.TypeIs(p, typeof(T)), invoke, Expression.Constant(null, typeof(TProperty)));
var lambda = Expression.Lambda<Func<IBase, TProperty>>(iif, p);

对于Test2

代码语言:javascript
复制
var iif = Expression.IfThen(Expression.TypeIs(p2, typeof(T)), invoke);
var lambda = Expression.Lambda<Action<IBase, TProperty>>(iif, p2, p1);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56670252

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档