所以,我正在尝试使用表达式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;
}
有人能指出我正确的方向吗?
答案 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;
}