Associate attribute with code generated property in .net

后端 未结 4 501
遥遥无期
遥遥无期 2020-12-28 08:28

I wish to set an attribute on a public property in .NET, however I do not have access to the explicit property itself, as this has been code generated in another file.

相关标签:
4条回答
  • 2020-12-28 09:02

    Another option is to wrap the properties inside non-generated properties in the same class. Not ideal because you may end up having double properties but if you can make your generator make protected properties it'd be a pretty good approach.

    Just had to deal with this problem: Entity Framework generates classes, I want to serialize them to JSON with simpler names.

    // 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; }
    }
    

    and the add-on class:

    [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; }
        }
    } 
    
    0 讨论(0)
  • 2020-12-28 09:08

    Since the generated class is a partial class, the following should work:

    1. Create an interface that has this property declared in it, and decorate it with ValidateNonEmpty attribute.
    2. Create your own partial class with same name as the AutoGenerated class, and make this implement the interface that you just created.
    3. The property should now be decorated with that attribute

    For example:

    // 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; }
    }
    

    I got this idea from geekswithblogs.

    0 讨论(0)
  • 2020-12-28 09:21

    This is a known nuisance; you simply can't add metadata to the generated members.

    There are 6 options here (in order of increasing effort):

    • if you own the attribute, make it possible to declare it against the class, for example: [ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)] - then add multiple attributes to the partial class definition
    • use a virtual / interface / etc method to query this, rather than via attributes
    • sublass the generated type; override or re-declare the member, adding the metadata (really messy)
    • use a custom TypeDescriptionProvider to provide dynamic metadata (lots and lots of work) - assuming that the consumer respects TypeDescriptor; most binding-related consumers do, but for example, Expression (used by many LINQ providers) doesn't
    • change the code-generator / write your own
    • try to extend something like PostSharp to do the work (I haven't found a way to do this, but I've love to hear if you find a way!)

    I usually have success with the first option, unless it is a system-defined attribute ([DisplayName], etc). If [ValidateNonEmpty] is defined by dynamic data, then you might not be able to do this.

    0 讨论(0)
  • 2020-12-28 09:26

    This is a great solution, but it didn't work for my problem. I'm using EF 6 with code-first generated classes from an existing database. One of the columns in a table is an IDENTITY with auto generated values. However, the generated partial class did not provide the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute needed to have the database generate the key. The result is the error "Cannot insert explicit value for identity column in table 'mytable' when IDENTITY_INSERT is set to OFF.". I tried your solution but it didn't work. But if I add the attribute to the original generated class, it does work. So I'm still trying to find a solution that does not require the modifying of the auto generated file.

    Here is the code I tried using your solution:

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

    original generated code:

    [Table("MyTable")]
    public partial class MyTable
    {
        [Key]
        [Column(Order = 1)]
        public int ID { get; set; }
    }
    
    0 讨论(0)
提交回复
热议问题