C# 在ModelValidationProvider中使用反射有多糟糕?

C# 在ModelValidationProvider中使用反射有多糟糕?,c#,reflection,asp.net-mvc-3,data-annotations,C#,Reflection,Asp.net Mvc 3,Data Annotations,我目前正试图找到一种方法来简化使用来自DataAnnotations的ErrorMessage。在阅读了这个主题之后,最常见的解决方案(基于每个属性创建一个类,并自动定义ErrorMessageResourceName和ErrorMessageResourceType)并不让我满意。因此,我决定重写ModelValidationProvider来实现这一点 不幸的是,我不得不在我的解决方案中求助于反射,我很清楚这种技术的性能成本。我已经在考虑“缓存”每个modelValidator的属性信息,这

我目前正试图找到一种方法来简化使用来自DataAnnotations的ErrorMessage。在阅读了这个主题之后,最常见的解决方案(基于每个属性创建一个类,并自动定义ErrorMessageResourceName和ErrorMessageResourceType)并不让我满意。因此,我决定重写ModelValidationProvider来实现这一点

不幸的是,我不得不在我的解决方案中求助于反射,我很清楚这种技术的性能成本。我已经在考虑“缓存”每个modelValidator的属性信息,这样我就不必每次都运行GetProperties。使用这种方法还有其他建议/批评吗

public class LocalizedDataAnnotationsModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        var baseReturn = base.GetValidators(metadata, context, attributes);
        var resourceManager = Validation.ResourceManager;
        var culture = Thread.CurrentThread.CurrentUICulture;

        foreach (var modelValidator in baseReturn)
        {
            var type = modelValidator.GetType();
            var attributeProp = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(x => x.Name == "Attribute");

            var attribute = attributeProp.GetValue(modelValidator, null) as ValidationAttribute;

            if (attribute != null)
            {
                if (string.IsNullOrEmpty(attribute.ErrorMessage))
                {
                    var attributeName = attribute.GetType().Name.Replace("Attribute", string.Empty);
                    attribute.ErrorMessage = resourceManager.GetString(attributeName, culture);
                }
            }
        }

        return baseReturn;
    }
}
公共类LocalizedDataAnnotationsModelValidatorProvider:DataAnnotationsModelValidatorProvider
{
受保护的重写IEnumerable GetValidator(ModelMetadata元数据、ControllerContext上下文、IEnumerable属性)
{
var baseReturn=base.GetValidators(元数据、上下文、属性);
var resourceManager=Validation.resourceManager;
var culture=Thread.CurrentThread.CurrentUICulture;
foreach(baseReturn中的var modelValidator)
{
var type=modelvalidater.GetType();
var attributeProp=type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(x=>x.Name==“属性”);
var attribute=attributeProp.GetValue(modelValidator,null)作为ValidationAttribute;
if(属性!=null)
{
if(string.IsNullOrEmpty(attribute.ErrorMessage))
{
var attributeName=attribute.GetType().Name.Replace(“attribute”,string.Empty);
attribute.ErrorMessage=resourceManager.GetString(attributeName,区域性);
}
}
}
返回基返回;
}
}

在这里,您最好/最简单的选择是在应用程序启动时迭代程序集,并缓存您可以缓存的内容。

好的,缓存属性信息是一种方法,但我建议您查看Reflection.Emit

下面是一个如何加速动态属性访问(而不是标准反射GetValue)的好例子:


通过使用Reflection.Emit,您将获得更好的性能。

一点也不差。别担心

使用类似的技术,我很少从反射中获得超过60毫秒的开销。不要过早地优化

一旦该应用程序投入生产,您几乎可以保证从优化存储过程和媒体文件大小以缩短加载时间中获得更大的收益。

这是不好的,因为它是不必要的。 我看不出你从反思中得到了什么,而你只能这样做:

foreach(baseReturn中的var modelValidator) { if(modelValidator是DataAnnotationsModelValidator){ var属性=((DataAnnotationsModelValidator)modelValidator).attribute; if(attribute!=null&&string.IsNullOrEmpty(attribute.ErrorMessage)){ var attributeName=attribute.GetType().Name.Replace(“attribute”,string.Empty); attribute.ErrorMessage=resourceManager.GetString(attributeName,区域性); } } } }

更新,这不起作用,因为
属性
属性是
受保护的内部
。但是,你仍然可以:

  foreach(var validationAttribute in attributes.OfType<ValidationAttribute>()){
            var attributeName = attribute.GetType().Name.Replace("Attribute", string.Empty);
            attribute.ErrorMessage = resourceManager.GetString(attributeName, culture);
  }
foreach(attributes.OfType()中的var validationAttribute){
var attributeName=attribute.GetType().Name.Replace(“attribute”,string.Empty);
attribute.ErrorMessage=resourceManager.GetString(attributeName,区域性);
}

迭代60毫秒十次,现在您只需半秒钟。我会在你的回答中强调这个风险。@Slappy,如果你去1000000000次?你的观点是什么?这在ModelBinding期间执行一次。我要补充的是,当我得到60毫秒时,表单在几个嵌套对象上有大约60个字段。问题清楚地说明了“使用这种方法还有其他建议/批评吗?”我的观点是,你的回答是误导性的,因为你像固定成本一样抛出60毫秒。我只是说要指出,这种成本不是恒定的,可以变化。就在前几天,我优化了一个网站,因为进行反射来建立一个EDMX连接字符串,导致了巨大的性能损失。这个“成本”只有25毫秒,但是当多次调用时产生了巨大的影响。。。我为大多数验证器添加了一个简单的缓存,让我们看看这是怎么回事。如果它成为性能瓶颈,我将尝试反射。按建议发射。您无法访问该属性。它被伪装成内部保护。嘿,它起作用了。。。谢谢至少我在这个过程中学会了反射、发射和超描述符。