Properties/Fields eines (unbekannten) CustomAttributes einer Methode einer geladenen Assembly auslesen

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von TRiViUM.

    Properties/Fields eines (unbekannten) CustomAttributes einer Methode einer geladenen Assembly auslesen

    Neu

    Hallo liebe Community,

    ich spiele gerade etwas mit dem Reflections-Namespace herum und habe mich gefragt, ob es damit auch möglich ist, Felder/Properties von CustomAttributes auszulesen, welche einer Methode zugeordnet sind.

    Leider bekomme ich immer die Fehlermeldung, dass das Objekt nicht mit dem Zieltyp übereinstimmt (Zeile 33).

    Hier der Quellcode der Bibliothek, welche ich als Assembly lade:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. namespace EducationLibrary
    3. {
    4. public class SpecialMethodAttribute : Attribute
    5. {
    6. public string Field_ID;
    7. public string Property_ID { get; set; }
    8. }
    9. public class EducationLibrary
    10. {
    11. #region methods
    12. #region private
    13. private void PrivateMethod()
    14. {
    15. }
    16. #endregion
    17. #region internal
    18. internal void InternalMethod()
    19. {
    20. }
    21. #endregion
    22. #region public
    23. public void PublicMethod()
    24. {
    25. }
    26. #endregion
    27. #endregion
    28. #region functions
    29. #region private
    30. private bool PrivateBoolFunction()
    31. {
    32. return true;
    33. }
    34. #endregion
    35. #region internal
    36. internal bool InternalBoolFunction()
    37. {
    38. return true;
    39. }
    40. #endregion
    41. #region public
    42. public bool PublicBoolFunction()
    43. {
    44. return true;
    45. }
    46. public bool PublicBoolFunctionWithParameter(bool par1)
    47. {
    48. return true;
    49. }
    50. public bool PublicBoolFunctionWithParameters(bool par1, bool par2)
    51. {
    52. return true;
    53. }
    54. [SpecialMethod(Field_ID = "34284", Property_ID = "123")]
    55. public bool PublicBoolFunctionWithParametersAndAttribute(bool par1, bool par2)
    56. {
    57. return true;
    58. }
    59. #endregion
    60. #endregion
    61. }
    62. }


    Und hiermit lade ich die Assembly:
    Spoiler anzeigen

    C#-Quellcode

    1. private void ReadAssembly()
    2. {
    3. using( var dialog = new OpenFileDialog())
    4. {
    5. dialog.Filter = "Assembly files|*.dll;*.exe";
    6. if( dialog.ShowDialog() == DialogResult.OK)
    7. {
    8. #region *** Load assembly ***
    9. var assembly = Assembly.LoadFile( dialog.FileName );
    10. #endregion
    11. #region *** Get types ***
    12. var types = assembly.GetExportedTypes();
    13. if (types.Length > 0)
    14. {
    15. foreach (var type in types)
    16. {
    17. #region *** Get methods ***
    18. var methods = type.GetMethods( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );
    19. if (methods.Length > 0)
    20. {
    21. foreach (var method in methods)
    22. {
    23. #region *** Get custom attributes ***
    24. var customAttributes = method.GetCustomAttributes( true );
    25. if (customAttributes.Length > 0)
    26. {
    27. foreach (var customAttribute in customAttributes)
    28. {
    29. var attributeType = customAttribute.GetType();
    30. var props = customAttribute.GetType().GetProperties();
    31. foreach (var prop in props)
    32. {
    33. MessageBox.Show( prop.GetValue( prop.ReflectedType ).ToString() );
    34. }
    35. }
    36. }
    37. #endregion
    38. }
    39. }
    40. #endregion
    41. }
    42. }
    43. #endregion
    44. }
    45. }
    46. }


    Mit Debugger kann ich das alles schön sehen:


    Edit:
    Ich kenne hier zwar das Attribute in der DLL, allerdings möchte ich auch externe, mir unbekannte .Net-DLLs laden können, wo ich erstmal keine Attribute kenne...

    Was mache ich falsch?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „TRiViUM“ ()

    Neu

    Ich mache das immer so

    VB.NET-Quellcode

    1. Imports System.Reflection
    2. Imports System.Runtime.CompilerServices
    3. Public Class SpecialMethodAttribute : Inherits Attribute
    4. Public Field_ID As String
    5. Private Field_Private As String
    6. Public Property Property_ID As String
    7. Public Sub New(id As String, priv As String, prop As String)
    8. Me.Field_ID = id
    9. Me.Field_Private = priv
    10. Me.Property_ID = prop
    11. End Sub
    12. End Class
    13. Module Module1
    14. Public Sub Main()
    15. Dim sma = New SpecialMethodAttribute("äne", "mene", "mü")
    16. Dim field = sma.GetType.GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Static)
    17. Dim fieldprop = sma.GetType.GetProperties()
    18. Dim Field_ID = field(0).GetValue(sma)
    19. Dim Field_Private = field(1).GetValue(sma)
    20. Dim Property_ID = field(2).GetValue(sma)
    21. Dim Type_Id = fieldprop(1).GetValue(sma) 'Erbung Attribute
    22. Stop
    23. End Sub
    24. End Module


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Neu

    Ich hatte scheinbar vergessen zu schreiben, dass mir das Attribute der DLL, die ich lade, generell unbekannt ist -> hab's im Post #1 hinzugefügt.Klar, ich hab's in der Beispiel-DLL selbst erstellt und kenne es, das war aber nur für Testzwecke.Wenn ich später eine mir unbekannte .Net-DLL lade, kenne ich keinerlei Attribute, die ich beim Abfragen übergeben kann.

    ErfinderDesRades schrieb:

    prop.GetValue(null).ToString()

    Das erzeugt einen anderen Fehler: System.Reflection.TargetException: "Die nicht-statische Methode erfordert ein Ziel.

    @exc-jdbi
    Danke für Deinen Lösungsansatz.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    Neu

    Ich weiss was du meinst.

    Das ist gar nicht mal so ein grosses Problem. Ich hab dazu immer eine Dictionary erstellt, wo alle Members also Fields, Properties und sogar Methoden erwähnt sind. Dazu habe ich mir eine ganz spezielle Klasse mit den entsprechenden Funktionen gemacht.

    Den Ansatz über die For-Schleifen ist genau der Richtige, damit lassen sich die gewünschten Infos sammeln. Das setzen wie auch das lesen der Felder ist der nächste Schritt und die funktionieren bei allen in etwa gleich.

    Ist schon ein bisschen Arbeit, aber es lohnt sich für spätere Projekte, sofern man dann noch mit Reflection weiter zu tun hat.

    Freundliche Grüsse

    exc-jdbi

    Neu

    @exc-jdbi
    Achso, dann hab ich das falsch interpretiert.

    In Deinem Code-Beispiel wird ja eine neue Instanz des Attributes erstellt, dessen Felder/Properties ausgelesen werden.
    Das möchte/kann ich in meinem Fall ja gar nicht.

    So würden ja die ursprünglich zugewiesenen Felder/Properties in der geladenen Assembly verloren gehen.

    Muss der Typ (/Klasse), wo die Methode mit dem CustomAttribute drin ist, dafür erst instanziiert werden?
    Weil sonst sind doch auch die Felder/Properties nicht zugewiesen, oder?

    Den Ansatz mit der Dictionary verfolge ich weiter, das hatte ich auch vor.

    Neu

    Soviel ich mich da noch erinnern kann, bin ich über Assembly gegangen. Müsste es heute Abend kurz ausgraben.

    Ich glaube das waren die Schlüsselwörter für das Laden der Assambly
    Assembly.Load()
    .GetExportedTypes
    ConstructorInfo
    .CreateInstance
    ConstructorInfo.Invoke()

    Ich denk es gibt noch ein paar, aber z.B. mit dieser ConstructorInfo.Invoke() konnte ich dann die Methoden ausführen. Es führt kein Weg vorbei, das vorherige Erfassen der Struktur in der Assembly muss gemacht werden, damit man dieses zu sich holen kann, um dann die gewünschten Sachen zu machen. Also Lesen, Schreiben, Ausführen etc. von Members.

    Damals habe ich das so gemacht, wahrscheinlich gibt es bessere Ansätze. Jetzt sehe ich auch gerade, du arbeitest mit FX 1.0-2.0. Wie weit das dort möglich ist weiss ich nicht, den ich habe damals mit FX 4.0 gearbeitet.

    Freundliche Grüsse

    exc-jdbi









    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „exc-jdbi“ ()

    Neu

    Hab gerade noch mal geschaut, was mit Assembly alles so möglich ist und spontan nix gefunden.
    Okay, dann bin ich mal gespannt... :rolleyes:

    Ups, da haste ja noch was editiert :D
    Ah okay, da experimentiere ich doch gleich mal mit rum, danke :saint:

    exc-jdbi schrieb:

    du arbeitest mit FX 1.0-2.0

    Ja, allerdings plane ich, dies auf mind. FX 4.5 hochzusetzen, da man ja nur Assemblies laden kann, die höchstens mit dem FX kompiliert wurden, wie die Anwendung, die diese laden soll...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TRiViUM“ ()

    Neu

    EDR das was du zeigst ist absolut korrekt. Ich hab einfach nur die Erfahrung gemacht, wenn man die Instanz holt über Assembly und das Property nicht explizit setzt (oder vom Program explizit gesetzt worden ist), so kommt immer "Null" raus. Und wenn man das nicht weiss, sucht man lange. So kann es kurz getestet werden.

    C#-Quellcode

    1. var instance = Activator.CreateInstance(ASM.GetType("namespace.Classname", constructorparameter1,constructorparameter2, etc.);
    2. instance.GetType().GetProperty("PropertyName").SetValue(instance, PropertyValue (z.B. ein string) ,null);
    3. ....
    4. ....
    5. var prop_value = instance.GetType().GetProperty("PropertyName").GetValue(instance, null);


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „exc-jdbi“ ()