Связать атрибут с генерируемым кодом свойства в .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
Ответы
Ответ 1
Это известная неприятность; вы просто не можете добавлять метаданные к сгенерированным членам.
Здесь есть 6 вариантов (в порядке возрастания усилий):
- если у вас есть атрибут, дайте ему возможность объявить его против класса, например:
[ValidateNonEmpty("Name", "Name is required", ExecutionOrder = 1)]
- затем добавьте несколько атрибутов в определение частичного класса
- используйте метод virtual/interface/etc для запроса этого, а не через атрибуты
- сублимировать сгенерированный тип; переопределить или повторно объявить участника, добавив метаданные (действительно грязные)
- используйте пользовательский
TypeDescriptionProvider
для предоставления динамических метаданных (много и много работы) - при условии, что потребитель уважает TypeDescriptor
; большинство связанных с привязанностью потребителей, но, например, Expression
(используется многими поставщиками LINQ) не
- измените генератор кода/напишите свой собственный
- попробуйте сделать что-то вроде PostSharp для выполнения этой работы (я не нашел способ сделать это, но я очень рад услышать, если вы найдете способ!)
Обычно у меня есть успех с первым параметром, если только это не системный атрибут ([DisplayName]
и т.д.). Если [ValidateNonEmpty]
определяется динамическими данными, возможно, вы не сможете этого сделать.
Ответ 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.
Ответ 3
Это отличное решение, но это не сработало для моей проблемы. Я использую 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; }
}
Ответ 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; }
}
}