2011-01-27 11 views
8

Nie jestem pewien, czy to jest możliwe, widziałem:
Change Attribute's parameter at runtime.
Mój przypadek jest bardzo podobny, ale staram się zmienić atrybut klasy w Runtime:Modyfikowanie klasy atrybutu na Runtime

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

Jedna z odpowiedzi brzmiała:

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") 

Zmieniono do formatu bardziej czytelny, dzięki Marc Gravell:

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

Wszystko jest dobrze, gdy za pomocą TypeDescriptor ale przy użyciu:

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

Nazwa ma "Zmień mnie" tekst.
Czy istnieje sposób na zmianę tego atrybutu w środowisku wykonawczym?

Edit:
muszę to dla linq2sql w projektanta wygenerowany kod ma schematu DB. Chcę użyć domyślnego schematu użytkownika bez użycia mapowania XML lub zmienić wygenerowanego kodu (tabela jest wciąż w fazie rozwoju i często się zmienia).

Kod projektant:

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

Chcę atrybut być:

[TableAttribute(Name="MyTable")] 

Teraz mam wykopane w kodzie ramowego i myślę Linq2Sql używa:

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

Kiedy używam TypeDescriptor do zmiany atrybutu, wartość nie jest zmieniona w GetCustomAttributes.

+2

Dlaczego chcesz to zrobić? Atrybuty mają dostarczać metadane, nie wiele więcej. Dlaczego nie przyjąć podejścia polegającego na posiadaniu "listy reguł", która jest początkowo zapełniana atrybutami i zmieniana? – vcsjones

+0

Co próbujesz osiągnąć? Lokalizowanie tekstu w kategorii? –

+0

@vcsjones wierzyć lub nie, są chwile, w których trzeba dodać, zmienić lub usunąć atrybuty w czasie wykonywania. Musiałem to zrobić, aby dodać konwerter do powiązań WPF, aby były serializowane, a nie oceniane. – Will

Odpowiedz

0

Jeśli używasz odbicie, to nie całkiem tak - odbicie atrybuty nie mogą być podstawione - tylko komponent model widok wywiera swój wpływ TypeDescriptor. Możesz jednak podklasę CategoryAttribute do swoich celów. Szczególnie użyteczne dla 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; 
    } 
} 
+0

Niestety nie mogę zmienić oryginalnego atrybutu ani utworzyć własnej wersji. Linq2Sql oczekuje TableAttribute. –

0

Musisz zakodować atrybut tak, aby obsługiwał wartości środowiska wykonawczego. Na przykład atrybuty sprawdzania poprawności obsługują internacjonalizację wiadomości poprzez ustawienie typu zasobu i łańcucha zasobów w przeciwieństwie do statycznego ciągu komunikatów.

Innym podejściem jest użycie kontenera IOC, takiego jak StructureMap lub Unity, w celu zapewnienia obiektu/usługi, który dostarcza wartości.

Jeśli nie chcesz powiązać atrybutu z konkretnym kontenerem, użyj opakowania Common ServiceLocator udostępnionego przez grupę Patterns and Practices.

2

Unikanie odbicia całkowicie, można to zrobić poprzez 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 
    } 
} 
+1

Cóż, to naprawdę nie działa, gdy używam TypeDescriptor, otrzymuję zmienioną wartość. Ale linq2sql (do czego potrzebuję tego) używa (TableAttribute []) table.GetCustomAttributes (typeof (TableAttribute), true), który pobiera oryginalną wartość ... –

Powiązane problemy