Frage an c#, reflection, custom-attributes, runtime – Ändern Sie den Parameter des benutzerdefinierten Attributs zur Laufzeit

12

Ich benötige den Parameter des Änderungsattributs zur Laufzeit. Ich habe mein Problem zu einem einfachen Beispiel vereinfacht.

Attributklasse:

<code>    [AttributeUsage(AttributeTargets.Property)]
    public class MyAttribute : Attribute
    {
        public string Name { get; set; }
    }
</code>

Einfache Entität, die Eigenschaften mit Attributen dekoriert hat:

<code>    public class MyEntity
    {
        [MyAttribute(Name="OldValue1")]
        public string Data1{ get; set; }

        [MyAttribute(Name = "OldValue2")]
        public string Data2 { get; set; }
    }
</code>

Ich habe eine Instanz der Klasse MyEntity erstellt. Ich kann den Wert der Objekteigenschaften ändern, aber den Wert der Attributeigenschaft Name für die Objektentität nicht. Ist es möglich?

Wert der Eigenschaft einer Objektentität, die ich mit diesem Teil des Codes ändern kann:

<code>                entityProp.SetValue(entity,"NewData",null);
</code>

Ich verändere jedoch nicht den Wert der Eigenschaft Name des Attributs für die Objektentität

Das funktioniert nicht:

<code>attProp.SetValue(attribute,"NewData",null);
</code>

Wert der Eigenschaft Name ist noch original.

Hier ist der gesamte Testcode. Danke für die Hölle.

<code>    [TestMethod]
    public  void Test()
    {
        var entity = new MyEntity
                         {
                             Data1 = "OldData",
                             Data2 = "OldData"
                         };

        PropertyInfo[] entityProps = entity.GetType().GetProperties();

        foreach (var entityProp in entityProps)
        {
            var attribute = Attribute.GetCustomAttribute(entityProp, typeof (MyAttribute)) as MyAttribute;

            if (attribute != null)
            {
                //get attribute’s property NAME
                PropertyInfo attProp= attribute.GetType().GetProperty("Name");

                //get entity property value
                var propertyValue = entityProp.GetValue(entity, null);

                //get attribute’s property NAME value
                var atributeNameValue = attProp.GetValue(entity, null);

                TestContext.WriteLine(string.Format("property name:{0} property value: {1} : atribute name value: {2}\n", 
                    entityProp.Name, propertyValue, atributeNameValue)); 

                //change values
                entityProp.SetValue(entity,"NewData",null);

                //how can I change value of property Name on object entity ?
                attProp.SetValue(attribute,"NewData",null);

            }

        }

        TestContext.WriteLine(string.Format("After change\n"));

        foreach (var entityProp in entityProps)
        {
            var attribute = Attribute.GetCustomAttribute(entityProp, typeof(MyAttribute)) as MyAttribute;

            if (attribute != null)
            {

                PropertyInfo attProp = attribute.GetType().GetProperty("Name");

                var propertyValue = entityProp.GetValue(entity, null);
                var atributeNameValue = attProp.GetValue(entity, null);

                TestContext.WriteLine(string.Format("property name:{0} property value: {1} : atribute name value: {2}\n",
                    entityProp.Name, propertyValue, atributeNameValue));
            }
        }



    }
</code>

BEARBEITET: Ich lösche den ursprünglichen Beitrag und füge eine sehr einfache, übersichtliche Probe hinzu. Es tut uns leid

Randnotiz: Warum fängt Ihre zweite Methode Exception ab und wirft sie dann aus? David Nelson

Deine Antwort

2   die antwort
11

Sie können Attribute zur Laufzeit nicht ändern. Sie sind in die Metadaten der Assembly eingebettet. Ihre Methode ändert den internen Status einer bestimmten Instanz. Wenn Sie das Attribut jedoch erneut laden, wird eine andere Instanz angezeigt.

@Mike Ich habe mich sehr bemüht, eine Lösung zu finden, um Attribute zur Laufzeit zu ändern. Selbst mit meinen 1337 Haxxor-Fähigkeiten fand ich nichts. Diese Antwort gefällt Ihnen vielleicht nicht, ist aber leider richtig. payo
@ Toastrackenigma es ist nicht "einfach falsch" oder eine andere Art von falsch, wie die Antworten auf die Frage, die Sie verlinkt haben. David Nelson
Sie haben Recht, ich habe den ganzen Tag damit verbracht, aber konnte keine Lösung finden, weil dieses Problem keine Lösung hat. :( also Attribute Bereich nur lesbar? Mike
Das ist schlicht falsch. Sehen:stackoverflow.com/questions/51269/… Toastrackenigma
Sie sagen mit Bestimmtheit, dass es keine Möglichkeit gibt, dies zu tun, da die Antworten auf diese andere Frage, die Reflektion usw. verwenden, für viele dieser Fälle tatsächlich funktionieren - sie haben mein Problem definitiv gelöst. Ich bin zwar nicht damit einverstanden, dass Attribute Teil der Assembly sind, aber ich bin nicht damit einverstanden, die Idee, sie zur Laufzeit zu ändern, allgemein zu streichen, indem ich sage, dass dies unmöglich ist, wenn es zumindest in einigen Fällen zumindest Möglichkeiten gibt, dies zu tun ( oder zumindest etwas daserscheint wie es tut), vor allem, wenn es ein Problem wie OPs lösen könnte. Toastrackenigma
4

Dies ist bei Reflection nicht möglich, da (wie bereits erwähnt) die Metadaten festgelegt sind. Teilweise ist dies jedoch mit TypeDescriptor möglich, mit dem Attribute zur Laufzeit hinzugefügt und ersetzt werden können und vollständige alternative Modelle (TypeDescriptionProvider usw.) bereitgestellt werden können. Dieser Ansatz wird von keinem Code beachtet, der Reflektion verwendet, aber jeder Code, der TypeDescriptor verwendet (in der Regel Datenbindung und anderer UI-Code), wird die Änderungen bemerken.

Hinweis TypeDescriptor funktioniert nur mit einem Attributtyp pro Typ / Element. Attribute mit mehreren Instanzen werden nicht gut unterstützt.

Verwandte Fragen