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

时间:2018-04-22 23:10:41

标签: c# expression func

所以,我正在尝试使用表达式atm。得到以下代码: 代码工作正常,除了一件事:我需要将ForeignMeyProperty.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;
        }

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

2 个答案:

答案 0 :(得分:1)

使用Object作为类型。然后你可以在运行时通过getType()检查类型,并在检查后转换为正确的类型。或使用动态来避免施放。

答案 1 :(得分:0)

所以,我按照你的建议做了并改为使用了对象。它现在有效。 下面的代码适用于从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 model) { try { if (setForeignKeyActionList == null) setForeignKeyActionList = SetForeignKeyProperties(); setForeignKeyActionList.ForEach(action => action(Repository, model.SourceModel)); Repository.SaveItem(model); return RedirectToAction("Index"); } catch(Exception ex) { ModelState.AddModelError("Error", ex); return View(Repository.GetEditableItem(id)); } }

这是基于您使用对象类型的建议的修订代码 protected List< Action< 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 (var ForeignKeyProperty in foreignKeyProperties) { var foreignKeyIdProperty = viewModelType.GetProperties().SingleOrDefault(x => x.Name == ForeignKeyProperty.Name + "Id"); //ForeignKeyProperty.SetValue(model, 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);

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

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