Изменение атрибута класса во время выполнения - PullRequest
8 голосов
/ 27 января 2011

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

[Category("Change me")]
public class Classic
{
    public string Name { get; set; }
}

Один из ответов был:

Dim prop As PropertyDescriptor = TypeDescriptor
    .GetProperties(GetType(UserInfo))("Age")
Dim att As CategoryAttribute = DirectCast(
     prop.Attributes(GetType(CategoryAttribute)),
     CategoryAttribute)
Dim cat As FieldInfo = att.GetType.GetField(
     "categoryValue",
      BindingFlags.NonPublic Or BindingFlags.Instance)
cat.SetValue(att, "A better description")

Изменен на более читаемый формат, благодаря Марку Гравеллу:

TypeDescriptor.AddAttributes(table, new Category{ Name = "Changed" });

Все хорошо при использовании TypeDescriptor, но при использовании:

var attrs = (Category[])typeof(Classic).GetCustomAttributes(
    typeof(Category),
    true);
attrs[0].Name

Имя имеет текст "Измени меня".
Есть ли способ изменить этот атрибут во время выполнения?

Edit:
Мне нужно это для Linq2Sql в конструкторе сгенерированный код имеет схему БД. Я хочу использовать схему пользователя по умолчанию без использования сопоставления XML или изменить сгенерированный код (таблица все еще находится в стадии разработки и часто изменяется).

Код конструктора:

[global::System.Data.Linq.Mapping.TableAttribute(Name="DbSchema.MyTable")]
public partial class MyTable

Я хочу, чтобы атрибут был:

[TableAttribute(Name="MyTable")] 

Теперь я копался в коде фреймворка и думаю, что linq2sql использует:

TableAttribute[] attrs = (TableAttribute[])typeof(MyTable)
   .GetCustomAttributes(typeof(TableAttribute), true);

Когда я использую TypeDescriptor для изменения атрибута, значение не изменяется в GetCustomAttributes.

Ответы [ 3 ]

2 голосов
/ 27 января 2011

Избегая отражения полностью , вы можете сделать это через TypeDescriptor:

using System;
using System.ComponentModel;
using System.Linq;
[Category("nice")]
class Foo {  }
static class Program
{
    static void Main()
    {
        var ca = TypeDescriptor.GetAttributes(typeof(Foo))
              .OfType<CategoryAttribute>().FirstOrDefault();
        Console.WriteLine(ca.Category); // <=== nice
        TypeDescriptor.AddAttributes(typeof(Foo),new CategoryAttribute("naughty"));
        ca = TypeDescriptor.GetAttributes(typeof(Foo))
              .OfType<CategoryAttribute>().FirstOrDefault();
        Console.WriteLine(ca.Category); // <=== naughty
    }
}
0 голосов
/ 27 января 2011

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

Другой подход заключается в использовании контейнера IOC, такого как StructureMap или Unity, для предоставления некоторыхобъект / сервис, который предоставляет значения.

Если вы не хотите связывать свой атрибут с конкретным контейнером, используйте обертку Common ServiceLocator, предоставленную группой Patterns and Practices.

0 голосов
/ 27 января 2011

Если вы используете отражение , то не совсем так - отражение атрибуты не могут быть заменены - только компонент-модель влияет на TypeDescriptor.Тем не менее, вы можете подкласс CategoryAttribute для ваших целей.Особенно полезно для i18n.

using System.ComponentModel;
using System;
[MyCategory("Fred")]
class Foo {  }
static class Program
{
    static void Main()
    {
        var ca = (CategoryAttribute)Attribute.GetCustomAttribute(typeof(Foo), typeof(CategoryAttribute));
        Console.WriteLine(ca.Category);
              // ^^^ writes "I was Fred, but not I'm EVIL Fred"
    }
}
class MyCategoryAttribute : CategoryAttribute
{
    public MyCategoryAttribute(string category) : base(category) { }
    protected override string GetLocalizedString(string value)
    {
        return "I was " + value + ", but not I'm EVIL " + value;
    }
}
...