<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      大叔手記(8):Interface Attributes != Class Attributes

      2011-12-16 08:58  湯姆大叔  閱讀(3268)  評論(1)    收藏  舉報

      問題

      事情來源于很早之前Team成員一個不規(guī)范的設(shè)計,在MVC3的項目上,由于所有的Model都需要有一些基本的名稱或者操作,加之應(yīng)用了DI,所以就想當(dāng)然地定義了一個接口,里面包含了一些接口屬性和方法,可突然有一天要求在這些屬性上應(yīng)用一些驗證約束和授權(quán),于是接口代碼改成了這樣:

          public interface IModel
      {
      [Required]
      string ModelName { get; set; }

      [Permission(Configuration = "Debug")]
      void OutputMessage();
      }

      實現(xiàn)類,幾乎沒有改變,只是在需要驗證的屬性上添加了Required類似的attribute:

          public class SearchCriteria : IModel
      {
      public string ModelName { get; set; }

      [Required]
      public string Keyword { get; set; }

      // 更多Model屬性

      public void OutputMessage()
      {
      // 這里是處理代碼
      }
      }

       

      可是后來應(yīng)用的時候,發(fā)現(xiàn)接口里定義的驗證約束根本不起作用,后來開始一路查找。

      分析

      看了MVC的源碼,找到了2個相關(guān)的地方。

      1.查詢所有的Attributes(AssociatedValidatorProvider里定義了GetValidators抽象方法)

              private IEnumerable<ModelValidator> GetValidatorsForType(ModelMetadata metadata, ControllerContext context) {
      return GetValidators(metadata, context, GetTypeDescriptor(metadata.ModelType).GetAttributes().Cast<Attribute>());
      }

      private IEnumerable<ModelValidator> GetValidatorsForProperty(ModelMetadata metadata, ControllerContext context) {
      ICustomTypeDescriptor typeDescriptor = GetTypeDescriptor(metadata.ContainerType);
      PropertyDescriptor property = typeDescriptor.GetProperties().Find(metadata.PropertyName, true);
      if (property == null) {
      throw new ArgumentException(
      String.Format(
      CultureInfo.CurrentCulture,
      MvcResources.Common_PropertyNotFound,
      metadata.ContainerType.FullName, metadata.PropertyName),
      "metadata");
      }

      return GetValidators(metadata, context, property.Attributes.OfType<Attribute>());
      }

      2.DataAnnotationsModelValidatorProvider類實現(xiàn)了GetValidators抽象方法,節(jié)選代碼:

          // Produce a validator for each validation attribute we find
      foreach (ValidationAttribute attribute in attributes.OfType<ValidationAttribute>()) {
      DataAnnotationsModelValidationFactory factory;
      if (!AttributeFactories.TryGetValue(attribute.GetType(), out factory)) {
      factory = DefaultAttributeFactory;
      }
      results.Add(factory(metadata, context, attribute));
      }


      可是從里面根本沒有發(fā)現(xiàn)有什么特殊處理的地方,那為何就不能把接口的Attributes取出來呢?

      后來看到Brad Wilson的一篇文章,才發(fā)現(xiàn)原來CLR對于基類和接口的處理是不一樣的,基類是繼承的,所以所有基類里出現(xiàn)的方法,屬性等在子類實現(xiàn)類里具有同樣的效果,但是接口是不一樣的,接口是用來實現(xiàn)的,要求子類必須實現(xiàn),但接口有2種實現(xiàn)方式:隱式和顯式。

      隱式:也就是我們上面的代碼使用的方式,用public的屬性和方法去實現(xiàn)接口,但是重要的,實現(xiàn)類里的public的屬性和方法和接口里聲明的那些完全不是一樣的東西,雖然他們有相同的簽名,通過反射代碼,我們可以看出兩者之間完全不一樣,因為這個不同,所以說接口屬性和方法上的metadata Attribute不會作用在實現(xiàn)類上,也就會出現(xiàn)我們文章開頭的問題。


      這些規(guī)則其實是CLR定義好的,和MVC無關(guān),查看MVC里關(guān)于model綁定的源碼,我們可以知道,在進(jìn)行model綁定的時候,我們是基于實現(xiàn)類類型的,而不是接口類型,因為action里的參數(shù)一般來說都是實現(xiàn)類類型(MVC隱式創(chuàng)建),而不是接口類型(MVC實現(xiàn)不了),所以在上述2段MVC源碼里通過反射查找Attributes的時候只能查詢到實現(xiàn)類類型的Attributes。

      改進(jìn)

      知道了原因,我們就得改代碼了,第一種最簡單的方式就是在子類實現(xiàn)類上需要驗證的屬性上逐一添加相應(yīng)的驗證類型Attributes,后來覺得其實Model綁定也沒必要非要得DI掛上鉤,所以改成了抽象類,如下:

          public abstract class ModelBase
      {
      [Required]
      string ModelName { get; set; }

      [Permission(Configuration = "Debug")]
      void OutputMessage();
      }

      這樣,就不用在子類實現(xiàn)類里逐一添加這些Attributes了。

      當(dāng)然,如果你非要使用接口,而又不想在子類里逐一添加Attributes,那恐怕你只有在MVC里使用自己的自定義ModelValidatorProvider了,在保留原來代碼的基礎(chǔ)上,加上一段特殊的邏輯,把該model所實現(xiàn)的接口逐一判斷一下,看看里面有沒有帶ValidationAttribute,偽代碼如下:

              public List<ValidationAttribute> GetValidationAttributesFromInterface()
      {
      //以類型SearchCriteria為例

      List<ValidationAttribute> attributes = new List<ValidationAttribute>();

      typeof(SearchCriteria)
      .GetInterfaces()
      .ToList()
      .ForEach(t =>
      {
      attributes.AddRange(
      t.GetProperty("ModelName").
      GetCustomAttributes(true).OfType
      <ValidationAttribute>());
      });

      return attributes;
      }

      參考文檔:http://bradwilson.typepad.com/blog/2011/08/interface-attributes-class-attributes.html

      同步與結(jié)束語

      本文已同步至目錄索引:《大叔手記全集》

      大叔手記:旨在記錄日常工作中的各種小技巧與資料(包括但不限于技術(shù)),如對你有用,請推薦一把,給大叔寫作的動力

      主站蜘蛛池模板: 久久成人国产精品免费软件| 欧美成人精品一级在线观看| 制服丝袜美腿一区二区| 激情偷乱人成视频在线观看| 亚洲AV成人片不卡无码| 欧美xxxxhd高清| 亚洲日韩性欧美中文字幕| 日本久久一区二区免高清| 福利视频一区二区在线| 国产精品丝袜一区二区三区| 国产老熟女无套内射不卡| 4399理论片午午伦夜理片| 五月综合激情婷婷六月| 婷婷六月色| 国产人妻熟女呻吟在线观看| 亚洲乱码精品中文字幕| 亚洲色欲色欱WWW在线| 久久精品国产九一九九九| 亚洲激情一区二区三区视频| 四虎在线播放亚洲成人| 成人免费A级毛片无码网站入口| 国产香蕉尹人综合在线观看| 国产免费爽爽视频| 国产精品揄拍一区二区久久| 樱花草视频www日本韩国| 成人影片一区免费观看| 亚洲中文久久久久久精品国产| 91福利国产午夜亚洲精品| 国产97人人超碰CAO蜜芽PROM | 日韩精品亚洲专在线电影| 国产免费午夜福利片在线| 国产一区二区日韩经典| 蜜桃麻豆www久久囤产精品| 久久久无码精品亚洲日韩蜜桃| 国产精品欧美福利久久| 精品亚洲一区二区三区在线播放| 亚洲成人av在线资源网| 亚洲精品免费一二三区| 人人妻人人爽人人澡av| 国产精品老熟女乱一区二区| 国产成人一区二区不卡|