C# 属性的反射集值
我有两门课:C# 属性的反射集值,c#,reflection,C#,Reflection,我有两门课: public class CustomerViewModel { public SystemViewModel system { get;set; } } public class SystemViewModel { public bool isReadOnly { get; set; } } 在methodcontroller操作中,我有一个自定义的filter属性,它执行一些代码并确定用户是否具有只读或写访问权限。此属性可应用于跨多个控制器的多个操作 到目前为止,使
public class CustomerViewModel {
public SystemViewModel system { get;set; }
}
public class SystemViewModel {
public bool isReadOnly { get; set; }
}
在methodcontroller操作中,我有一个自定义的filter属性,它执行一些代码并确定用户是否具有只读或写访问权限。此属性可应用于跨多个控制器的多个操作
到目前为止,使用反射,我可以通过以下方式访问模型:
var viewModel = filterContext.Controller.ViewData.Model;
我无法将此模型强制转换为CustomerViewModel,因为在不同的操作上,它可能类似于SalaryViewModel。我所知道的是,任何需要readonly属性的模型都将具有SystemViewModel属性
从我的自定义过滤器中,我需要一种能够更改readonly值的方法
到目前为止,我有:
public override void OnActionExecuted(ActionExecutedContext filterContext) {
var viewModel = filterContext.Controller.ViewData.Model;
var systemViewModelPropertyInfo = model.GetType()
.GetProperties()
.FirstOrDefault(p => p.PropertyType == typeof(SystemViewModel));
if (systemViewModelPropertyInfo != null) {
// Up to here, everything works, systemViewModelPropertyInfo is of
// type PropertyInfo, and the systemViewModelPropertyInfo.PropertyType
// shows the SystemViewModel type
// If we get here, the model has the system property
// Here I need to try and set the IsReadOnly property to true/false;
// This is where I need help please
}
}
已解决
感谢所有参与帮助解决这个问题的人。特别感谢Julián Urbano提供了我一直在寻找的解决方案。
以下是我在过滤器中生成的代码:
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
try
{
var viewModel = filterContext.Controller.ViewData.Model;
var systemViewModelPropertyInfoCount = viewModel.GetType().GetProperties().Count(p => p.PropertyType == typeof(SystemViewModel));
if(systemViewModelPropertyInfoCount == 1)
{
var systemViewModelPropertyInfo = viewModel.GetType().GetProperties().First(p => p.PropertyType == typeof(SystemViewModel));
if(systemViewModelPropertyInfo != null)
{
var systemViewModel = systemViewModelPropertyInfo.GetValue(viewModel, null) as SystemViewModel;
if(systemViewModel != null)
{
var admin = GetAdmin(filterContext.HttpContext.User.Identity.Name);
if(admin != null && _adminService.HasPermission(admin, _privilege, Access.Level.ReadWrite))
systemViewModel.ReadOnly = false;
else
systemViewModel.ReadOnly = true;
}
}
} else if(systemViewModelPropertyInfoCount > 1)
{
throw new Exception("Only once instance of type SystemViewModel allowed");
}
}
catch (Exception exception)
{
Log.Error(MethodBase.GetCurrentMethod(), exception);
filterContext.Controller.TempData["ErrorMessage"] = string.Format("Technical error occurred");
filterContext.Result = new RedirectResult("/Error/Index");
}
finally
{
base.OnActionExecuted(filterContext);
}
}
我无法将此模型强制转换为CustomerViewModel,因为在不同的操作上,它可能类似于SalaryViewModel。我所知道的是,任何需要readonly属性的模型都将具有SystemViewModel属性
选项1
在我看来,最好的选择是编写如下接口:
public interface IWithSystemViewModel {
SystemViewModel System {get;}
}
并从类中实现它,类似于:
public class CustomerViewModel : IWithSystemViewModel{
public SystemViewModel System { get;set; }
}
public class SalaryViewModel : IWithSystemViewModel{
public SystemViewModel System { get;set; }
}
因此,您可以强制转换它并访问isReadOnly
属性:
IWithSystemViewModel viewModel = filterContext.Controller.ViewData.Model as IWithSystemViewModel;
if(viewModel!=null){
viewModel.System.isReadOnly ...
}
选项2
如果要坚持使用反射,请执行以下操作:
var viewModel = filterContext.Controller.ViewData.Model;
SystemViewModel theSystem = viewModel.GetType().GetProperty("system")
.GetValue(viewModel, null) as SystemViewModel;
theSystem.isReadOnly ...
棘手的事情:在代码中,选择类型为SystemViewModel
的属性。但是,如果对象实际上有几个您不知道的SystemViewModel
属性,该怎么办?你确定你访问的是正确的吗?您可以强制它们使用相同的名称,但这与使用上面选项1中的接口类似
我肯定会选择第一种
var viewModel = new CustomerViewModel();
var systemViewModelPropertyInfo = viewModel.GetType()
.GetProperties()
.FirstOrDefault(p => p.PropertyType == typeof(SystemViewModel));
if (systemViewModelPropertyInfo != null) {
var systemViewModelProperty = systemViewModelPropertyInfo.GetValue(viewModel, null) as SystemViewModel;
// get the desired value of isReadOnly here...
var isReadOnly = false;
// here, systemViewModelProperty may be null if it has not been set.
// You can decide what to do in that case. If you need a value to be
// present, you'll have to do something like this...
if (systemViewModelProperty == null) {
systemViewModelPropertyInfo.SetValue(viewModel, new SystemViewModel { isReadOnly = isReadOnly }, null);
}
else {
systemViewModelProperty.isReadOnly = isReadOnly;
}
}
我无法将此模型强制转换为CustomerViewModel,因为在不同的操作上,它可能类似于SalaryViewModel。我所知道的是,任何需要readonly属性的模型都将具有SystemViewModel属性
选项1
在我看来,最好的选择是编写如下接口:
public interface IWithSystemViewModel {
SystemViewModel System {get;}
}
并从类中实现它,类似于:
public class CustomerViewModel : IWithSystemViewModel{
public SystemViewModel System { get;set; }
}
public class SalaryViewModel : IWithSystemViewModel{
public SystemViewModel System { get;set; }
}
因此,您可以强制转换它并访问isReadOnly
属性:
IWithSystemViewModel viewModel = filterContext.Controller.ViewData.Model as IWithSystemViewModel;
if(viewModel!=null){
viewModel.System.isReadOnly ...
}
选项2
如果要坚持使用反射,请执行以下操作:
var viewModel = filterContext.Controller.ViewData.Model;
SystemViewModel theSystem = viewModel.GetType().GetProperty("system")
.GetValue(viewModel, null) as SystemViewModel;
theSystem.isReadOnly ...
棘手的事情:在代码中,选择类型为SystemViewModel
的属性。但是,如果对象实际上有几个您不知道的SystemViewModel
属性,该怎么办?你确定你访问的是正确的吗?您可以强制它们使用相同的名称,但这与使用上面选项1中的接口类似
我肯定会选择第一种
var viewModel = new CustomerViewModel();
var systemViewModelPropertyInfo = viewModel.GetType()
.GetProperties()
.FirstOrDefault(p => p.PropertyType == typeof(SystemViewModel));
if (systemViewModelPropertyInfo != null) {
var systemViewModelProperty = systemViewModelPropertyInfo.GetValue(viewModel, null) as SystemViewModel;
// get the desired value of isReadOnly here...
var isReadOnly = false;
// here, systemViewModelProperty may be null if it has not been set.
// You can decide what to do in that case. If you need a value to be
// present, you'll have to do something like this...
if (systemViewModelProperty == null) {
systemViewModelPropertyInfo.SetValue(viewModel, new SystemViewModel { isReadOnly = isReadOnly }, null);
}
else {
systemViewModelProperty.isReadOnly = isReadOnly;
}
}
也就是说,如果您实现了一个接口,整个过程可能会更容易
public interface IHaveSystemViewModel {
SystemViewModel system { get; set; }
}
var model = viewModel as IHaveSystemViewModel;
if (model != null) {
// again, you need to make sure you actually have a reference here...
var system = model.system ?? (model.system = new SystemViewModel());
system.isReadOnly = false; // or true
}
也就是说,如果您实现了一个接口,整个过程可能会更容易
public interface IHaveSystemViewModel {
SystemViewModel system { get; set; }
}
var model = viewModel as IHaveSystemViewModel;
if (model != null) {
// again, you need to make sure you actually have a reference here...
var system = model.system ?? (model.system = new SystemViewModel());
system.isReadOnly = false; // or true
}
你说得很对。我已成功实施了您的选项2。非常感谢你@TALON乐于助人,但认真考虑我对选项2中的危险的评论(在编辑的答案)中,我对代码进行了轻微的调整,以找到类型为“StimeVIEWMIDE”的属性,而不是寻找属性的名称。其次,我检查了返回的属性的数量,如果超过1,我抛出一个异常。我将在下面发布我的代码以供评论。我还希望它是强类型的,因此我决定不使用SystemViewModel的字符串表示。你说得很对。我已成功实施了您的选项2。非常感谢你@TALON乐于助人,但认真考虑我对选项2中的危险的评论(在编辑的答案)中,我对代码进行了轻微的调整,以找到类型为“StimeVIEWMIDE”的属性,而不是寻找属性的名称。其次,我检查了返回的属性的数量,如果超过1,我抛出一个异常。我将在下面发布我的代码以供评论。我还希望这是强类型的,因此我决定不使用SystemViewModel的字符串表示。谢谢!我喜欢你添加SystemViewModel的方式,如果它不存在的话。我同意该接口会更好,严格来说更正确,因为它不会“隐藏”任何实现。只是我个人的喜好,保持我的模型尽可能干净和简单。谢谢!我喜欢你添加SystemViewModel的方式,如果它不存在的话。我同意该接口会更好,严格来说更正确,因为它不会“隐藏”任何实现。这只是我个人的喜好,让我的模型尽可能干净和简单。