Свяжите атрибут со свойством, созданным кодом в .NET

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

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

public virtual string Name { get; set; }

Я хочу установить это:

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

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

Цитаты: http://blogs.oosterkamp.nl/blogs/jowen/archive/2008/10/16/metadatatype-attribute.aspxhttp://blogs.msdn.com/davidebb/archive/2008/06/16/dynamic-data-and-the-associated-metadata-class.aspx

Есть ли способ установить эти атрибуты (даже через web.config!), Не касаясь сгенерированного кода класса?

Заранее спасибо, Грэм

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
17
0
4 605
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

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

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

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

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

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

GONeale 19.01.2009 09:14

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

GONeale 19.01.2009 09:14

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

GONeale 19.01.2009 09:16

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

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

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

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

Я получил эту идею от компьютерщики.

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

secretwep 29.10.2014 20:42

Это отличное решение, но оно не сработало для моей проблемы. Я использую EF 6 с классами, созданными первым кодом из существующей базы данных. Один из столбцов в таблице - это ИДЕНТИФИКАЦИЯ с автоматически сгенерированными значениями. Однако сгенерированный частичный класс не предоставил атрибут [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; }
}

Другие вопросы по теме