2009-01-19 5 views
16

Я хочу установить атрибут для открытого свойства в .NET, однако у меня нет доступа к самому явному свойству, так как это был код, сгенерированный в другом файле.Связанный атрибут с генерируемым кодом в .net

У меня есть это поле:

public virtual string Name { get; set; } 

Я желаю, чтобы установить это:

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

Мой класс помечен как частичный, но вы не можете иметь частичные свойства. Я думал, что я что-то сделал с классом MetadataType, который является новой функцией Dynamic Data и DataAnnotations, но, увы, я чувствую, что он может использоваться только с динамическими данными, это правда?

Цитирование: 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!), Не касаясь кода, сгенерированного класса?

Спасибо заранее, Graham

ответ

22

Это известная неприятность; вы просто не можете добавлять метаданные к сгенерированным членам.

Есть 6 вариантов здесь (в порядке возрастания усилий):

  • , если у вас есть атрибут, сделать возможным объявить его против класса, например: [ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)] - затем добавить несколько атрибутов в определение частичного класса
  • использовать метод virtual/interface/etc для запроса этого, а не через атрибуты
  • sublass сгенерированный тип; переопределить или повторно объявить участника, добавив метаданные (действительно беспорядочно)
  • использовать таможню TypeDescriptionProvider для предоставления динамических метаданных (много и много работы) - при условии, что потребитель уважает TypeDescriptor; большинство вяжущих связанный с потребителей делать, но, например, Expression (используется многими поставщиками LINQ) не
  • изменения код-генератор/написать свое собственное
  • пытаются продлить что-то вроде PostSharp, чтобы сделать работу (убежище I «т нашел способ сделать это, но я люблю слушать, если вы найдете способ!)

Я обычно имеют успех с первым вариантом, если это не является атрибутом системы определяется ([DisplayName] и т.д.). Если [ValidateNonEmpty] определяется динамическими данными, возможно, вы не сможете этого сделать.

+0

Благодаря Марк, я думал, что это может быть так. Мне удалось выполнить итерацию свойств моего объявленного класса «MetadataType», в тот момент, когда я хотел узнать об атрибутах, и просто сопоставляю имя свойства «meta» с реальным свойством. – GONeale

+0

Это не то же самое, что я могу понять, какие истинные атрибуты я понимаю, но для того, что мне нужно, похоже, что это послужит цели в этом случае. Это здорово. – GONeale

+0

Надеюсь, это имеет смысл. Теперь я могу увидеть, был ли объявлен и действителен ли атрибут проверки. Теперь я просто надеюсь, что мне не нужно накладных расходов, используя класс атрибутов «MetadataType», вместо того, чтобы делать свой собственный, который просто говорит ему, в какой класс искать свойства. – GONeale

1

Другой вариант - обернуть свойства внутри неотрожденных свойств в том же классе. Не идеально, потому что у вас могут быть двойные свойства, но если вы можете сделать свой генератор защищенными свойствами, это будет очень хороший подход.

Просто нужно было решить эту проблему: 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; } 
    } 
} 
6

Поскольку создаваемый класс представляет собой частичный класс, должно работать:

  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.

+0

Думаю, вам понадобится каждое отдельное свойство из вашего базового класса, которое также будет помещено в интерфейс, утомительное упражнение, если у вас много сгенерированных классов и много свойств. – secretwep

2

Это отличное решение, но это не помогло решить мою проблему. Я использую EF 6 с генерируемыми кодами классами из существующей базы данных. Одним из столбцов в таблице является IDENTITY с автоматически генерируемыми значениями. Однако сгенерированный неполный класс не предоставил атрибут [DatabaseGenerated (DatabaseGeneratedOption.Identity)], необходимый для генерации базы данных. Результатом является ошибка «Невозможно вставить явное значение для столбца идентификации в таблице« mytable », если для параметра IDENTITY_INSERT установлено значение« OFF ».». Я попробовал ваше решение, но оно не сработало. Но если я добавлю атрибут к исходному сгенерированному классу, он работает. Поэтому я все еще пытаюсь найти решение, которое не требует модификации автоматически созданного файла.

Вот код, который я пытался использовать свое решение:

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