Могу ли я определить свойства в частичных классах, а затем пометить их атрибутами в другом частичном классе?

84

Есть ли способ получить сгенерированный файл кода следующим образом:

public partial class A {
public string a {get; set;}
}

а затем в другом файле:

public partial class A {
[Attribute("etc")]
public string a {get; set;}
}

Чтобы я мог создать класс из базы данных, а затем использовать несгенерированный файл для его разметки?

Крис МакКолл
источник
Сколько «генерируется из базы данных»? Только определения свойств или еще код?
Snemarch
1
Короткий ответ, нет. Длинный ответ, дубликат stackoverflow.com/questions/456624/… .
Кирк Уолл,
@snemarch: только определения свойств, я планирую сделать любой другой код вручную.
Крис Макколл,
1
Могли бы вы сделать с разделением интерфейса + реализации вместо частичного класса? Сгенерируйте интерфейс из базы данных, внедрите (и добавьте атрибуты) в реализацию.
Snemarch
да, это возможно, но с использованием метаданных можно получить другое частичное наследование этих метаданных
CyberNinja

Ответы:

33

Я видел нечто подобное в статье Скотта Гатри (ближе к концу) - хотя сам не пробовал.
http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

[MetadataType(typeof(Person_Validation))]
public partial class Person
{
    // Partial class compiled with code produced by VS designer
}

[Bind(Exclude="ID")]
public class Person_Validation
{
    [Required(ErrorMessage = "First Name Required")]
    [StringLength(50, ErrorMessage = "Must be under 50 characters")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "Last Name Required")]
    [StringLength(50, ErrorMessage = "Must be under 50 characters")]
    public string LastName { get; set; }

    [Required(ErrorMessage = "Age Required")]
    [Range(0, 120, ErrorMessage = "Age must be between 0 and 120")]
    public int Age { get; set; }

    [Required(ErrorMessage = "Email Required")]
    [Email(ErrorMessage = "Not a valid email")]
    public string Email { get; set; }
}
Дэн Думитру
источник
10
Этот ответ заслуживает упоминания, но это не общее решение вопроса, поставленного ОП. Потребители атрибутов все еще должны знать, что нужно искать класс метаданных - то есть эти атрибуты не будут возвращены Attribute.GetCustomAttribute (...). (К счастью для многих случаев использования, потребители написаны MS, и в определенных ситуациях это сработает.)
Кирк Уолл,
1
Это решение НЕ решает проблему. Почему мы стремимся украсить элементы в другом файле? Потому что класс ПЕРЕЗАПИСАН при каждом запуске конструктора. Таким образом, ваш атрибут [MetaDataType ...будет очищаться каждый раз при
2
@Desolator - Идея в том, что вы не помещаете MetadataTypeатрибут в файл, созданный дизайнером, вы помещаете его в другой файл, где определен частичный класс Person.
Дэн Думитру
1
проблема с этим решением в том, что класс должен быть частичным
CyberNinja
85

Вот решение, которое я использовал для таких случаев. Это полезно, когда у вас есть автоматически сгенерированные классы, которые вы хотите украсить атрибутами. Допустим, это автоматически сгенерированный класс:

public partial class UserProfile
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
}

И, скажем, я хотел бы добавить атрибут, чтобы указать, что UserId является ключом. Затем я бы создал частичный класс в другом файле, например:

[Table("UserProfile")]
[MetadataType(typeof(UserProfileMetadata))]
public partial class UserProfile
{
    internal sealed class UserProfileMetadata
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
    }
}
Жан-Франсуа Бошан
источник
Отличное решение. Я знал, что вы можете украсить частичный класс атрибутами в нескольких файлах и даже добавить интерфейсы и унаследованный класс к его объявлению, но я не подключался к MetadataTypeатрибуту. Отлично сработано!
Pflugs
Что, если я хочу добавить атрибут в конструктор UserProfile?
Botis
2
MetadataTypeне существует в .NET Core
WoIIe 05
2
.net использует ядроModelMetadataType
YLJ
1
Поддержка @Dave должна появиться в .NET Core 3.0
Роджер Уиллкокс,
2

Это мой ответ:
разные файлы классов, или вы можете объединить метаданные в одном файле, но сохранить пространство имен одинаковым ... чтобы они могли видеть друг друга, очевидно.

имейте в виду, что при обновлении модели, например при добавлении дополнительных столбцов, вам также необходимо обновить класс проекта.

--your model class
public partial class A {
    public string a {get; set;}
}

--your project class 
public class Ametadata {
     [Attribute("etc")]
     public string a {get; set;}
}


[MetadataType(typeof(Ametadata))]
public partial class A
{
}
CyberNinja
источник
1

Вам нужно определить частичный класс для своего Aкласса, как показано ниже.

using System.ComponentModel.DataAnnotations;

// your auto-generated partial class
public partial class A 
{
    public string MyProp { get; set; }
}

[MetadataType(typeof(AMetaData))]
public partial class A 
{

}

public class AMetaData
{
    [System.ComponentModel.DefaultValue(0)]
    public string MyProp { get; set; }
}
Масуд Дарвишян
источник
0

Не как таковое; компилятор будет жаловаться на то, что член определен в нескольких частях. Однако, поскольку использование настраиваемых атрибутов по своей природе является отражающим, вы можете определить класс «метаданных» и использовать его для содержания декораторов.

public class A
{
   public string MyString;
}

public class AMeta
{
   [TheAttribute("etc")]
   public object MyString;
}

...

var myA = new A();
var metaType = Type.GetType(myA.GetType().Name + "Meta");
var attributesOfMyString = metaType.GetMember("MyString").GetCustomAttributes();
KeithS
источник
1
Как часто актер, который добавляет атрибуты к своим свойствам, также является человеком, потребляющим их, и, следовательно, будет знать, что нужно искать магические «мета-классы»?
Кирк Уолл,
По моему опыту, довольно часто. Это не сработает для существующей аспектно-ориентированной структуры, но если вы украшаете свой домен, скажем, настраиваемыми атрибутами проверки, вы их ищете и можете определить где. Моя команда сделала именно это в одном из наших проектов. Главный недостаток - не искать другого класса; он поддерживает два параллельных класса при разработке, один функциональный, другой декоративный. Это было бы проблемой и для частичных классов, если бы вы могли изначально определить частичные поля / свойства.
KeithS