2010-09-23 5 views
55

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

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

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

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

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

+0

Сколько «генерируется из базы данных»? Только определения свойств или код? – snemarch

+1

Короткий ответ, нет. Длинный ответ, дубликат http://stackoverflow.com/questions/456624/associate-attribute-with-code-generated-property-in-net. –

+0

@snemarch: только определения свойств, я планирую сделать любой другой код вручную. –

ответ

24

Я видел что-то подобное сделано в статье Скотта Гатри (ближе к концу этого) - не пробовал это сам, хотя.
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; } 
} 
+5

Этот ответ стоит упомянуть, но это не общее решение вопроса, заданного ОП. Потребители атрибутов все еще должны знать, чтобы искать класс метаданных - т. Е. Эти атрибуты будут * not * возвращаться атрибутом.GetCustomAttribute (...). (К счастью для многих случаев использования, потребители написаны MS, и в определенных ситуациях это будет работать.) –

+0

Это решение НЕ решает проблему. Почему мы хотим украсить участников в другом файле? Потому что класс OVERWRITTEN каждый раз, когда дизайнер работает. Таким образом, ваш атрибут '[MetaDataType ...' будет очищаться каждый раз, когда дизайнер запускает – 2016-11-27 07:05:30

+0

@Desolator. Идея состоит в том, что вы не добавляете атрибут 'MetadataType' в файл, созданный дизайнером, вы помещаете его в другой файл, в котором определяется частичный класс 'Person'. –

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(); 
+1

Как часто бывает, что актер, добавляющий атрибуты к своим свойствам, также является человеком, который их потребляет, и поэтому будет знать, что нужно искать магические классы «Мета»? –

+0

Довольно часто, по моему опыту. Это не сработало бы для существующей аспектно-ориентированной структуры, но если бы вы украшали свой домен с помощью, скажем, пользовательских атрибутов проверки, вы ищете их и можете определить, где. Моя команда сделала именно это на одном из наших проектов. Главный недостаток - не поиск другого класса; он поддерживает два параллельных класса при разработке, один функциональный, другой декоративный. Это было бы проблемой и в частичных классах, если бы вы могли определить частичные поля/свойства в первую очередь. – KeithS

53

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

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

Работал как шарм! Спасибо!!! –

+0

Отличное решение. Я знал, что вы можете украсить частичный класс атрибутами в нескольких файлах и даже добавить в его объявление интерфейсы и унаследованный класс, но я не установил соединение с атрибутом «Метаданные». Отлично сработано! – Pflugs

+0

Что делать, если я хочу добавить атрибут в конструктор 'UserProfile'? – Botis

1

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

помните, когда вы обновляете свою модель, например добавляете больше столбцов, вам также нужно обновить класс проекта.

--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 
{ 
} 
0

Вы должны определить частичный класс для 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; } 
}