English 中文(简体)
使用反映创建表达式 <func>,\\\ 使用反映
原标题:Create an Expression<Func<,>> using reflection

Im 使用 Moq 创建数据集模型 。

我创建了一个小助手类,允许我有一个存储存储存储器,而不是一个让单位测试微风的数据库。 这样我就可以从我的模拟数据集中添加和删除项目, 这样我就可以测试我的插入和删除服务电话。

在模拟的设置期间, 我有一条线 看起来像下面的线

this.Setup(i => i.AcademicCycles).Returns(mockStore.GetList<AcademicCycle>());

我的模型有许多属性, 所以我想用反射来执行这个设置步骤。 我设法完成了该过程的 < code> returns 部分, 通过反射工作, 但我被卡在 ambda 方法上, 被困在 < code> Setup 上 。

setup 需要一个

Expression< Func< 目标模型Unitedwork, I 查询 < 与 i\gt; 对应的 {gt; i. AcademicCycles

并且我想以动态的方式创造这个。用反思,我有以下内容:

地产名称: "科学院圆环"

IQueryable< academicCycle> 类型

AcademicCycle 类型

我也有羊羔语句中 >i 的例子,该语句是 targetsMedel UnitedOf Work

最佳回答

动态创建表达式的代码将像这样 :

ParameterExpression parameter = Expression.Parameter(typeof (GoalsModelUnitOfWork), "i");
MemberExpression property = Expression.Property(parameter, "AcademicCycles");

var queryableType = typeof (IQueryable<>).MakeGenericType(typeof (AcademicCycle));
var delegateType = typeof (Func<,>).MakeGenericType(typeof (GoalsModelUnitOfWork), queryableType);

var yourExpression = Expression.Lambda(delegateType, property, parameter);

结果将具有想要的类型, 但问题在于 Expression.Lambda () 的返回类型是 Lambda Expression , 您无法执行投影到 Expression & lt; Func<... & gt; 的类型, 将它作为参数传送到您的设置功能, 因为您不知道 Func 的通用类型参数。 因此您也必须用反射方式引用 Setup 的方法 :

this.GetType().GetMethod("Setup", yourExpression.GetType()).Invoke(this, yourExpression);
问题回答

我决定破门而入 最终有了这个可怕的密码

我并不是反省专家,这只是第一次尝试让某些东西起作用。 我非常想知道人们还有什么其他方法,或者是否有任何翻版包装书库能让这些书库变得更好。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Moq;
using Xunit;

namespace MyExample
{
    public class Tests
    {
        [Fact]
        public void Test()
        {
            Dictionary<Type, object> data = new Dictionary<Type, object>
            {
                { typeof(IQueryable<Cycle>), new List<Cycle> { new Cycle { Name = "Test" } }.AsQueryable() },
                { typeof(IQueryable<Rider>), new List<Rider> { new Rider { Name = "1"}, new Rider { Name = "2" } }.AsQueryable() }
            };

            var mock = new Mock<IDataContext>();
            var setup = mock.GetType().GetMethods().Single(d => d.Name == "Setup" && d.ContainsGenericParameters);
            var param = Expression.Parameter(typeof(IDataContext), "i");
            foreach (var property in typeof(IDataContext).GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                // Build lambda
                var ex = Expression.Lambda(Expression.MakeMemberAccess(param, property), param);

                // Get generic version of the Setup method
                var typedSetup = setup.MakeGenericMethod(property.PropertyType);

                // Run the Setup method
                var returnedSetup = typedSetup.Invoke(mock, new[] { ex });

                // Get generic version of IReturns interface
                var iReturns = typedSetup.ReturnType.GetInterfaces().Single(d => d.Name.StartsWith("IReturns`"));

                // Get the generic Returns method
                var returns = iReturns.GetMethod("Returns", new Type[] { property.PropertyType });

                // Run the returns method passing in our data
                returns.Invoke(returnedSetup, new[] { data[property.PropertyType] });
            }

            Assert.Equal(1, mock.Object.Cycles.Count());
        }
    }

    public class Cycle
    {
        public string Name { get; set; }
    }

    public class Rider
    {
        public string Name { get; set; }
    }

    public interface IDataContext
    {
        IQueryable<Cycle> Cycles { get; set; }

        IQueryable<Rider> Riders { get; set; }
    }
}

此方法应该构造 lambda 表达式。 由于您正在以反射方式引用设置方法, 您不需要强烈类型的 lambda 表达式; 当您调用 < code> Invoke 时, 您会把它作为对象数组的一部分传递 :

    public LambdaExpression PropertyGetLambda(string parameterName, Type parameterType, string propertyName, Type propertyType)
    {
        var parameter = Expression.Parameter(parameterType, parameterName);
        var memberExpression = Expression.Property(parameter, propertyName);
        var lambdaExpression = Expression.Lambda(memberExpression, parameter);
        return lambdaExpression;
    }

我不认为您真的需要参数名称。 如果我说的没错, 您可以简化一点 :

    public LambdaExpression PropertyGetLambda(Type parameterType, string propertyName, Type propertyType)
    {
        var parameter = Expression.Parameter(parameterType);
        var memberExpression = Expression.Property(parameter, propertyName);
        var lambdaExpression = Expression.Lambda(memberExpression, parameter);
        return lambdaExpression;
    }




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...