Konstanten Weg-Kompilieren

  • C#

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Konstanten Weg-Kompilieren

    Hi,

    ich habe eine Klasse, die wie folgt aussieht:

    C#-Quellcode

    1. internal static class Foobar
    2. {
    3. public const string Abc = "testDastesttest";
    4. public const string Def = "DieDieDasDieDie";
    5. public const string Gij = "DasDasDasDasDasDas";
    6. }


    Diese Stringkonstanten verwende ich z. B. in einem Attributkonstruktor:

    C#-Quellcode

    1. [Obsolete(Foobar.Abc)]
    2. class Irgendwas


    Wenn ich jetzt als Release ohne Debug-Information/Konstante kompiliere, wird laut Reflektor/ILSpy daraus das:

    C#-Quellcode

    1. [Obsolete("testDastesttest")]
    2. class Irgendwas

    Genau so will ich es haben.

    Was mich jetzt aber stört, ist, dass die Deklarationen der Konstanten bestehen bleiben. d. h. die Klasse "Foobar" enthält immer noch die oben definierten Konstanten. Das macht ja auch Sinn.
    Das sieht im IL so aus:

    Quellcode

    1. .class private auto ansi abstract sealed beforefieldinit Localization
    2. extends [mscorlib]System.Object
    3. {
    4. .field public static literal string Abc = "testDastesttest"
    5. .field public static literal string Def = "DieDieDasDieDie"
    6. .field public static literal string Gij = "DasDasDasDasDasDas"
    7. }

    Ich möchte erreichen, dass diese verschwinden, sodass die Klasse leer ist (am besten möchte ich die komplette Klasse entfernen, da diese nur aus den Konstanten besteht).

    Ich stelle mir da etwas Präprozessor-Artiges ala #define Abc "testDastesttest" vor. Das geht in C# allerdings nicht. Gibt es vielleicht Compilerattribute, die man an die Konstanten kleben kann, damit der Compiler weiß, dass er diese nicht in die finale Assembly mit aufnehmen soll? Schließlich werden die Konstanten am Ende nirgends referenziert, was ja bedeutet, dass die Deklarationen eigentlich nicht mehr gebraucht werden (außer natürlich, wenn man sie für externe zugänglich macht).
    Hat jemand eine Idee, wie man sowas erreichen kann?

    nikeee
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „nikeee13“ ()

    Der C#-Präprozessor kann anscheinend keine Makros. Zumindest kann ich in der Dokumentation nichts dazu finden:
    msdn.microsoft.com/en-us/library/ed8yd1ha(v=vs.71).aspx
    Das #define definiert nur ein Symbol. Das kann aber nicht für ein Makro verwendet werden. Man kann nicht mal einen Wert für das Symbol festlegen. (Ist nur für die Conditional Compilation)

    Der Internal-Modifier ändert daran leider auch nichts.

    Benötigen tue ich das für die Lokalisierungen der Attribute und Exception-Messages. Das sieht dann z. B. so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. #define GERMAN
    2. internal static class Localization
    3. {
    4. #if GERMAN
    5. internal const string ArgumentExceptionInvalidPasswordLength = "Das Passwort hat eine ungültige Länge.";
    6. #else
    7. internal const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
    8. #endif
    9. }

    Es gibt bestimmt elegantere Wege dafür. Trotzdem wollte ich es mal so versuchen. Es sieht halt nicht so schön aus, wenn die Lokalisierungstexte als Konstanten "noch" in der Assembly enthalten sind. Wenn es aber nicht anders geht, muss ich mich wohl damit abfinden.


    @EDR:

    C#-Quellcode

    1. [Obsolete(Foobar.Abc)] //wird zu:
    2. .custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string) = (
    3. 01 00 0f 74 65 73 74 44 61 73 74 65 73 74 74 65
    4. 73 74 00 00
    5. )
    6. [Obsolete("testDastesttest")] //wird zu:
    7. .custom instance void [mscorlib]System.ObsoleteAttribute::.ctor(string) = (
    8. 01 00 0f 74 65 73 74 44 61 73 74 65 73 74 74 65
    9. 73 74 00 00
    10. )
    11. // baut sich wohl so auf:
    12. // 01 00 0f [textdaten] 00 00
    Es scheint also eine einfache Einsetzung stattzufinden.
    Von meinem iPhone gesendet

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

    Mir ist nicht bekannt, dass du die Teile eines Codes standartmäßig rauslöschen kannst.
    Ich find es zwar auch sinnlos, dass die Konstanten drinnen bleiben aber wenn du das sagst glaub ich dir das. Somit ist das Einzige was ich mir vorstellen kann was du tun kannst einen Postcompiler zu schreiben. Diesen kannst du dann im Postbuild aufrufen. Ich habe dabei recht gute Erfahrungen mit Mono.Cecil gemacht. Am einfachsten einfach über NuGet installieren. Du kannst damit recht einfach compilierte Assemblies verändern + die pdb Dateien neu generieren. Fraglich ist nur ob das wirklich notwendig ist.

    EDIT:
    Hab grad nachgeschaut. Konstanten werden im lokalen Bereich rausgelöscht. Ich denke jedoch, dass sie im globalen nicht rausgelöscht werden, da ne andere Anwendung auf diese Zugriffen könnte. Sprich in z.B. einer Bibliothek könnte es sein, dass eine externe Klasse,... darauf zugreifen möchte und wenn diese nicht mehr vorhanden sind geht dies natürlich nur schlecht.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Wie wär's eigentlich mit Resourcen? Du könntest ja für die unterstützten Kulturen, also eigentlich nur deutsch (Deutschland) und invariant, Satellitenassemblies anlegen. Dazu legst du in den Resourcen eine neue Datei Resources.<Kulturname>.resx ab. Der Kulturname ist dann halt z.B. de-DE oder de. Die "normale" Resources.resx wird dann für die invariante Kultur verwendet. Wenn dich da die Klasse dann immernoch stört, kannst du ja den Resourcemanager selbst verwalten und die Datei einfach aus der Kompilierung ausschließen (würde ich aber nicht machen, außer du legst bei der Verwaltung ebenfalls selbst Hand an).

    Gruß
    ~blaze~
    Soweit ich weiß sind die Ressourcen im Programm selber nur Properties. Das würde dann für die Exception-Messages funktionieren, nicht aber für die Attributtexte, da die zur Compiletime konstant sein müssen. Kann aber auch sein, dass ich mich bei dem Ressourcen-Kram irre.

    Ich bin gerade nicht am PC. Ich versuch es dann mal damit.
    Von meinem iPhone gesendet
    Verdammt. Daran hab' ich jetzt irgendwie nicht gedacht. :P Beim FW selbst stehts zumindest bei AppDomain.GetCurrentThreadId auf englisch da. Ich denk' mal, dass sich die die Arbeit nicht gemacht haben - und auch die Arbeit nicht, dass man ein Obsolete-Attribut mit Zugriff auf die Programmresourcen einführen könnte.

    Gruß
    ~blaze~
    Hier wurde es so gelöst, indem man vom eigentlichen Attribut ableitet und dann im konstruktor auf die Ressourcen zugreift.
    stackoverflow.com/a/7398740/785210
    Das finde ich aber nicht sonderlich elegant, bzw. zu Aufwändig.

    Naja, dann lass' ich es so, wie es jetzt ist.
    Von meinem iPhone gesendet

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „nikeee13“ ()

    Daran hatte ich auch schon gedacht, aber das geht ja wegen der Versiegelung nicht. Wär' aber wohl die schönste Lösung.
    Resourcen sind übrigens keine Properties, sondern Daten, die in der Anwendung enthalten sind und über einen ResourceManager bereitgestellt werden. System.Reflection.Assembly.GetManifestResource* z.B. kann man verwenden, um die Resourcen zu verwalten.

    Gruß
    ~blaze~