将属性与 .net 中的代码生成属性相关联
Posted
技术标签:
【中文标题】将属性与 .net 中的代码生成属性相关联【英文标题】:Associate attribute with code generated property in .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!)而不接触代码生成的类?
提前致谢, 格雷厄姆
【问题讨论】:
【参考方案1】:这是一个已知的麻烦;您根本无法将元数据添加到生成的成员中。
这里有 6 个选项(按努力增加的顺序):
如果您拥有该属性,则可以针对类声明它,例如:[ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)]
- 然后将多个属性添加到部分类定义中
使用虚拟/接口/等方法来查询这个,而不是通过属性来查询
子类化生成的类型;覆盖或重新声明成员,添加元数据(真的很乱)
使用自定义TypeDescriptionProvider
来提供动态元数据(大量工作)——假设消费者尊重TypeDescriptor
;大多数与绑定相关的消费者都这样做,但例如,Expression
(许多 LINQ 提供者使用)不这样做
更改代码生成器/自己编写
尝试扩展 PostSharp 之类的东西来完成这项工作(我还没有找到这样做的方法,但我很想听听您是否找到方法!)
我通常使用第一个选项会成功,除非它是系统定义的属性([DisplayName]
等)。如果[ValidateNonEmpty]
是由动态数据定义的,那么您可能无法做到这一点。
【讨论】:
谢谢 Marc,我想可能是这样。我已经设法遍历了我的“MetadataType”声明类的属性,此时我希望查询属性,我只是将“元”属性的名称与真实属性进行比较。 这与调查真实属性不同,我理解,但对于我需要的东西,它看起来可以在这种情况下达到目的。太棒了。 希望这是有道理的。我现在可以查看是否声明了验证属性并相应地工作。我现在只希望使用MetadataType
属性类而不是自己创建一个简单地告诉它查看属性的类没有开销。【参考方案2】:
由于生成的类是一个部分类,以下应该可以工作:
-
创建一个在其中声明此属性的接口,并使用 ValidateNonEmpty 属性对其进行装饰。
创建您自己的与 AutoGenerated 类同名的分部类,并使其实现您刚刚创建的接口。
现在应该使用该属性装饰属性
例如:
// 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;
【讨论】:
以上是关于将属性与 .net 中的代码生成属性相关联的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 RuntimeTypeModel 将 ProtoInclude 与 protobuf-net 中的类型相关联?