【问题标题】:Associate attribute with code generated property in .net将属性与 .net 中的代码生成属性相关联
【发布时间】:2010-10-02 04:19:50
【问题描述】:

我希望在 .NET 中为公共属性设置属性,但是我无权访问显式属性本身,因为这是在另一个文件中生成的代码。

我有这个字段:

public virtual string Name { get; set; }

我想设置这个:

[ValidateNonEmpty("Name is required", ExecutionOrder = 1)]
public virtual string Name { get; set; }

我的课程被标记为部分,但你不能有部分属性。我以为我对 MetadataType 类有所了解,这是 Dynamic Data 和 DataAnnotations 的一个新功能,但是我觉得它只能与 Dynamic Data 一起使用,这是真的吗?

引用: http://blogs.oosterkamp.nl/blogs/jowen/archive/2008/10/16/metadatatype-attribute.aspx http://blogs.msdn.com/davidebb/archive/2008/06/16/dynamic-data-and-the-associated-metadata-class.aspx

有什么方法可以设置这个属性(甚至通过 web.config!)而不接触代码生成的类?

提前致谢, 格雷厄姆

【问题讨论】:

    标签: .net attributes code-generation


    【解决方案1】:

    这是一个已知的麻烦;您根本无法将元数据添加到生成的成员中。

    这里有 6 个选项(按努力增加的顺序):

    • 如果您拥有该属性,则可以针对类声明它,例如:[ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)] - 然后将多个属性添加到部分类定义中
    • 使用虚拟/接口/等方法来查询这个,而不是通过属性来查询
    • 子类化生成的类型;覆盖或重新声明成员,添加元数据(真的很乱)
    • 使用自定义TypeDescriptionProvider 来提供动态元数据(大量工作)——假设消费者尊重TypeDescriptor;大多数与绑定相关的消费者都这样做,但例如,Expression(许多 LINQ 提供者使用)不这样做
    • 更改代码生成器/自己编写
    • 尝试扩展 PostSharp 之类的东西来完成这项工作(我还没有找到这样做的方法,但我很想听听您是否找到方法!)

    我通常使用第一个选项会成功,除非它是系统定义的属性([DisplayName] 等)。如果[ValidateNonEmpty] 是由动态数据定义的,那么您可能无法做到这一点。

    【讨论】:

    • 谢谢 Marc,我想可能是这样。我已经设法遍历了我的“MetadataType”声明类的属性,此时我希望查询属性,我只是将“元”属性的名称与真实属性进行比较。
    • 这与调查真实属性不同,我理解,但对于我需要的东西,它看起来可以在这种情况下达到目的。太棒了。
    • 希望这是有道理的。我现在可以查看是否声明了验证属性并相应地工作。我现在只希望使用MetadataType 属性类而不是自己创建一个简单地告诉它查看属性的类没有开销。
    【解决方案2】:

    由于生成的类是一个部分类,以下应该可以工作:

    1. 创建一个在其中声明此属性的接口,并使用 ValidateNonEmpty 属性对其进行装饰。
    2. 创建您自己的与 AutoGenerated 类同名的分部类,并使其实现您刚刚创建的接口。
    3. 现在应该使用该属性装饰属性

    例如:

    // Decorate the properties with attributes as required
    public interface IMyInterface
    {
        [ValidateNonEmpty("Name is required")]
        string Name { get; set; }
    }
    
    // This is the partial class I created, that implements the interface
    public partial class MyGeneratedClass : IMyInterface
    {    
    }
    
    // This is the auto-generated class
    public partial class MyGeneratedClass
    {
        public virtual string Name { get; set; }
    }
    

    我从geekswithblogs得到这个想法。

    【讨论】:

    • 我认为您需要将基类中的每个属性也放入接口中,如果您有许多生成的类和许多属性,这是一个乏味的练习。
    • 链接(实际上)已损坏。它重定向到 Geekswithblogs.net, the End of an Era.
    【解决方案3】:

    这是一个很好的解决方案,但它对我的问题不起作用。我将 EF 6 与现有数据库中的代码优先生成的类一起使用。表中的一列是具有自动生成值的 IDENTITY。但是,生成的部分类没有提供数据库生成密钥所需的 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 属性。结果是错误“当 IDENTITY_INSERT 设置为 OFF 时,无法在表 'mytable' 中插入标识列的显式值。”。我尝试了您的解决方案,但没有奏效。但是,如果我将属性添加到原始生成的类中,它确实有效。所以我还在努力寻找不需要修改自动生成文件的解决方案。

    这是我尝试使用您的解决方案的代码:

    public interface IMyTable
    {
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        int ID { get; set; }
    }
    
    public partial class MyTable : IMyTable
    {
    }
    

    原始生成代码:

    [Table("MyTable")]
    public partial class MyTable
    {
        [Key]
        [Column(Order = 1)]
        public int ID { get; set; }
    }
    

    【讨论】:

      【解决方案4】:

      另一种选择是将属性包装在同一类中的非生成属性中。不理想,因为您最终可能会拥有双重属性,但如果您可以让生成器生成受保护的属性,那将是一个非常好的方法。

      只需要处理这个问题:Entity Framework 生成类,我想用更简单的名称将它们序列化为 JSON。

      // GENERATED BY EF
      public partial class ti_Users
      {
          public ti_Users()
          {
              this.ti_CardData = new HashSet<ti_CardData>();
              this.ti_Orders = new HashSet<ti_Orders>();
          }
      
          protected int userId { get; set; }
          protected string userName { get; set; }
          protected string userEmail { get; set; }
          protected string userPassHash { get; set; }
          protected Nullable<System.DateTime> userLastLogin { get; set; }
          protected string userLastIP { get; set; } 
      
          public virtual ICollection<ti_CardData> ti_CardData { get; set; }
          public virtual ICollection<ti_Orders> ti_Orders { get; set; }
      }
      

      和附加类:

      [JsonObject(memberSerialization: MemberSerialization.OptIn)]
      public partial class ti_Users
      {
          [JsonProperty]
          public int UserId
          {
              get { return this.userId; }
              set { this.userId = value; }
          }
      
          [JsonProperty]
          public string Name
          {
              get { return this.userName; }
              set { this.userName = value; }
          }
      
          [JsonProperty]
          public string Email
          {
              get { return this.userEmail; }
              set { this.userEmail = value; }
          }
      
          [JsonProperty]
          public string PassHash
          {
              get { return this.userPassHash; }
              set { this.userPassHash = value; }
          }
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-13
        • 2016-10-09
        相关资源
        最近更新 更多