想要使 Func<UnknownType, bool> 其中 UnknownType 仅在运行时已知

Want to make Func<UnknownType, bool> where UnknownType is only known at runtime

所以,我正在试验表达式 atm。得到以下代码: 代码工作正常,除了一件事:我需要用 ForeignKeyProperty.PropertyType 替换 ViewModel 类型,这只在运行时才知道,在 var condition = Expression.Lambda < Func < ViewModel, bool> >

预期的最终结果:

ForeignKeyProperty.SetValue(model, repository.GetList  <ForeignKeyProperty.PropertyType >().Single(x => x.Id == model.Id));

protected List < Action < IVenturaRepository, ViewModel>> SetForeignKeyProperties<ViewModel>() where ViewModel : BaseViewModel
        {
            var viewModelType = typeof(ViewModel);
            var foreignKeyProperties = viewModelType.GetProperties().Where(x => x.PropertyType.IsSubclassOf(typeof(BaseViewModel)));
            var actions = new List < Action < IVenturaRepository, ViewModel>>();
            var repositoryType = typeof(IVenturaRepository);
            foreach(var ForeignKeyProperty in foreignKeyProperties)
            {
                var foreignKeyIdProperty = viewModelType.GetProperties().SingleOrDefault(x => x.Name == ForeignKeyProperty.Name + "Id");
                //ForeignKeyProperty.SetValue(model, repository.GetList<ViewModel>().Single(x => x.Id == model.Id));
                var listMethod = repositoryType.GetMethods().SingleOrDefault(x => x.Name == "GetList").MakeGenericMethod(ForeignKeyProperty.PropertyType);
                //Expression.Call(singleMethod,);
                var repositoryVariable = Expression.Parameter(repositoryType, "repository");
                var paramViewModelType = Expression.Parameter(viewModelType, "model");
                var paramForeignEntityId = Expression.Property(paramViewModelType, "Id");
                var listMethodCall = Expression.Call(repositoryVariable, listMethod);
                var modelParameter = Expression.Parameter(ForeignKeyProperty.PropertyType, "x");
                var foreignKeyTypeConstant = Expression.Constant(ForeignKeyProperty.PropertyType);
                var condition =
                    Expression.Lambda < Func < ViewModel, bool>>(
                        Expression.Equal(
                            Expression.Property(paramViewModelType, foreignKeyIdProperty.Name),
                            Expression.Convert(Expression.Property(modelParameter, "Id"),foreignKeyIdProperty.PropertyType)
                        ),
                        modelParameter
                    );
                //var singleMethod = typeof(Enumerable).GetMethods().SingleOrDefault(x => x.Name.Equals("SingleOrDefault") && x.GetParameters().Count() ==2).MakeGenericMethod(viewModelType);
                //var singleMethod = typeof(IEnumerable<ViewModel>).GetMethods().SingleOrDefault(x => x.GetParameters().Count() > 0).MakeGenericMethod(viewModelType);
                //var singleLambda = Expression.Lambda(Expression.Property(modelParameter, "Id"), modelParameter);
                var singleMethodCall = Expression.Call(typeof(Enumerable), "SingleOrDefault", new[] { ForeignKeyProperty.PropertyType },listMethodCall, condition);
                //var singleMethodCall = Expression.Call(listMethodCall, singleMethod, condition);
                var setMethod = ForeignKeyProperty.GetSetMethod();
                var oParameter = Expression.Parameter(viewModelType, "obj");
                var vParameter = Expression.Parameter(typeof(ViewModel),"value");
                var method = Expression.Call(oParameter,setMethod, singleMethodCall);
                var expression = Expression.Lambda<Action<IVenturaRepository, ViewModel>>(method);
                actions.Add(expression.Compile());
            }
            return actions;
        }

有人能给我指出正确的方向吗?

使用对象作为类型。然后您可以在运行时通过 getType() 检查类型,并在检查转换为正确的类型后检查类型。或者使用 dynamic 来避免转换。

所以,我按照您的建议做了,并改用了对象。现在可以了。 下面的代码在继承自 BaseController 的特定控制器中工作。 public override ActionResult Edit(long id, DeliveryEditViewModel model) { model.SourceModel.DeliveryRound = Repository.DeliveryRounds.Single(x => x.Id == model.DeliveryRoundId); model.SourceModel.Sale = Repository.Sales.Single(x => x.Id == model.SaleId); return base.Edit(id, model); } 想法是下面的代码在 BaseController 中工作: public virtual ActionResult Edit(long id, EditModel 模型) { 尝试 { 如果(setForeignKeyActionList == null) setForeignKeyActionList = SetForeignKeyProperties(); setForeignKeyActionList.ForEach(action => action(存储库, model.SourceModel)); Repository.SaveItem(型号); return RedirectToAction("Index"); } 赶上(异常前) { ModelState.AddModelError("Error", 例如); return视图(Repository.GetEditableItem(id)); } }</p> <p> 这是根据您使用对象类型的建议修改后的代码 受保护列表<操作<IVenturaRepository, ViewModel>> SetForeignKeyProperties() { var viewModelType = typeof(ViewModel); var foreignKeyProperties = viewModelType.GetProperties().Where(x => x.PropertyType.IsSubclassOf(typeof(BaseViewModel))); var actions = new List< Action< IVenturaRepository, ViewModel>>(); var repositoryType = typeof(IVenturaRepository); foreach(foreignKeyProperties 中的 var ForeignKeyProperty) { var foreignKeyIdProperty = viewModelType.GetProperties().SingleOrDefault(x => x.Name == ForeignKeyProperty.Name + "Id"); //ForeignKeyProperty.SetValue(模型, repository.GetList< OtherViewModel>().Single(x => x.Id == model.Id)); var listMethod = repositoryType.GetMethods().SingleOrDefault(x => x.Name == "GetList").MakeGenericMethod(ForeignKeyProperty.PropertyType); var repositoryVariable = Expression.Parameter(repositoryType, "repository"); var paramViewModelType = Expression.Parameter(viewModelType, "model"); var paramForeignEntityId = Expression.Property(paramViewModelType, "Id"); var listMethodCall = Expression.Call(repositoryVariable, listMethod);</p> <pre><code> var foreignKeyTypeConstant = Expression.Constant(ForeignKeyProperty.PropertyType); var objectType = Expression.Parameter(typeof(object), "model"); var modelParameter = Expression.Parameter(typeof(object), "x"); var expressionForeignKeyId = Expression.Property(paramViewModelType, foreignKeyIdProperty.Name); var expressionForeignEntityId = Expression.Convert(Expression.Property(Expression.Convert(modelParameter, ForeignKeyProperty.PropertyType), "Id"), foreignKeyIdProperty.PropertyType); var condition = Expression.Lambda<Func<object, bool>>( Expression.Equal( expressionForeignKeyId, expressionForeignEntityId ), modelParameter ); var singleMethodCall = Expression.Call(typeof(Enumerable), "SingleOrDefault", new[] { ForeignKeyProperty.PropertyType }, listMethodCall, condition); //var singleMethodCall = Expression.Call(listMethodCall, singleMethod, condition); var setMethod = ForeignKeyProperty.GetSetMethod(); //var oParameter = Expression.Parameter(viewModelType, "obj"); var vParameter = Expression.Parameter(typeof(ViewModel), "value"); var method = Expression.Call(paramViewModelType, setMethod, singleMethodCall); var lamdaParameterExpressions = new[] { repositoryVariable, paramViewModelType }; var expression = Expression.Lambda<Action<IVenturaRepository, ViewModel>>(method, lamdaParameterExpressions); actions.Add(expression.Compile()); } return actions; }