Entwickler-Ecke
C# - Die Sprache - Abstrakte Attribute
BLJ - Do 24.05.07 05:46
Titel: Abstrakte Attribute
Hallo zusammen,
wie allseits bekannt ist, kann man Attribute leider nicht als abstract definieren.
Ich habe nun einen Fall, wo dies sehr nützlich wäre:
1. eine Abstract Basis Klasse 'AbstractMessage'.
Sie definiert:
C#-Quelltext
1:
| protected Messages _MessageID; |
...
C#-Quelltext
1:
| public MessageID { get { return _MessageID; } } |
.
Dazu gibt's dann (bis zu) 255 Child-Klassen, bspw.
C#-Quelltext
1: 2: 3: 4:
| public ConcreteMessage { new public static const _MessageID = Messages.ConcreteMessage; } |
Gründe für diese Umsetzung:
-Es soll garantiert sein, dass jedes Child ein Attribut _MessageID haben soll, das Public ist.
Grund: Ich muss von aussen über Reflection drauf zugreifen. GGf. könnte ich den Reflection Teil auch in AbstractMessage ablegen, dann müsste es nur noch protected sein. Spielt aber eh keine Rolle.
-Es soll per Property 'MessageID' drauf zugegriffen werden können (eigentl. zwecks Information-Hiding, jetzt aber dank public Attribut eigentl. nuztlos)
Hat mir jemand einen konkreten Vorschlag wie ich das besser implementieren kann?
Ergo, wie kann ich sicherstellen, dass die Child-Klasse das Attribut Messages _MessageID implementiert
+ dieses aber eine static const ist?
Wenn ich eine static const in der AbstractMessage-Klasse implementiere, so ist diese gültig für alle Child-Messages, was dann super unnütz wäre.
Attribute kann man nicht abstract definieren...
es bleibt...?
in der Abstract Klasse eine abstrakte register-Methode definieren, die in jedem Child implementieren: Ziel: Soll in der AbstractMessage-Klasse (wäre dann halt nicht mehr ganz so abstract..) eine Liste (static Attribt der Abstract Classs) definieren, welche MsgIDs und Child-Messages miteinander verknüpft? Das wäre ja gottlos umständlich für ein prinzipiell so simples Problem.
bessere Ideen sind gesucht...
Grüsse,
BLJ
Moderiert von
raziel: C#-Tags hinzugefügt
Robert_G - Do 24.05.07 11:32
Statische Teile einer Klasse können weder virtuell noch abstrakt sein.
Sie werden ja nicht auf eine bestimmte Instanz ausgeführt und somit wäre es unmöglich eine bestimmte Implementierung zu finden.
Was du dir da überlegt hast, wirkt IMHO nicht so glücklich...
1: Ist es notwendig, dass das Feld statisch ist?
2: Öffentliche Bezeichner, die durch einen Unterstrich entstellt sind, verstoßen gegen die .Net API Guidelines. ;-)
3: Reflection ist so ziemlich die langsamste Art einen Wert abzufragen.
Um dir wirklich helfen zu können, müsste ich mehr über das wissen, was du da vorhast.
Eine Klasse, die nur dafür da ist einen String zu liefern ist ja sicherlich nur etwas Glue-Code für ein IOC-basiertes Design.
Erzähle uns etwas mehr darüber wofür die die MessageId benutzt und vielleicht finde wir einen Weg, der den Einsatz von Reflection minimiert und/oder einen Weg für dich findet diese IDs zu erzwingen...
btw: Felder in .Net als "Attribute" zu bezeichnen ist etwas gefährlich, da es bereits eine Objektgruppe gibt, die "Attribute" heißt. ;-)
BLJ - Do 24.05.07 14:02
Hi Robert,
danke für deine Antwort!
Die Messages sollen auf dem Com-Port verschickt werden.
Anhand der Message ID wird beim eintreffen ein Objekt erstellt. Momentan implementier ich in jeder Message à la:
C#-Quelltext
1:
| public static final _MessageID = Messages.TestMessage; |
public nur, da ich bei der Anwendungsinitialisation einmal mit Reflection alle Types mit .BaseClass = AbstractMessage durchgehe und diese so in meiner 'MessageFactory' (es ist kein echtes Factory Pattern, aber der Name passt ;-) ) registriere (mit MessageID + Konstruktor).
Ich möchte mehrere bspw. TestMessage : AbstractMessage erstellen können. Zum einen, weil ich darin zwei Konstruktoren habe (einen, um eine Nachricht, die gesendet werden soll, zu generieren, den anderen, um eine Nachricht, die angekommen ist zu 'erstellen'), anderseits weil ich die Messages ggf. in eine Queue setzen möchte.
Da ich eine geschlossene Einheit TestMessage habe, die sich die gemeinsame konstante Eigenschaft MessageID teilt, ist es nur logisch eine static final implementieren zu wollen.
Natürlich würde es auch ohne static gehen, nur; das wäre schlechtes OO-Design...
ich muss lediglich noch garantieren, dass diese Eigenschaft implementiert wird.
Das müsste ich sonst noch über ein seperates Interface IMessage machen?
C#-Quelltext
1: 2: 3: 4:
| public Interface IMessage { Messages _MessageID; } |
?
Das ist aber auch keine LKösung, da ich dann in jeder child-Klasse à la
C#-Quelltext
1:
| TestMessage : AbstractMessage, IMessage |
implementieren muss.
Asonsten ist die Message wieder auf Ebene Abstractmessage; womit wir wieder am Anfang sind.
sonstige Ideen?
Robert_G - Do 24.05.07 17:18
Brauchst du wirklich statische Member?
Wenn eine Klasse statischen Status braucht, gibt es dafür entweder wirklich triftige Gründe, oder man verbaut sich damit sinnlos Skalierbarkeit.
Hier ist mal eine einfache Idee,wie es gehen könnte:
Chrome-Quelltext
1: 2: 3: 4: 5: 6: 7:
| var context := new MessageContext();
context.RegisterMessagesFromAssembly(typeof(ConsoleApp).Assembly);
var message := context['miep!'];
Console.WriteLine(message.DoSomething()); |
Chrome-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| type IMessage = public interface property MessageId : String read;
method DoSomething : String; end;
HelloMessage = public sealed class(IMessage) public property MessageId : String read 'miep!';
method DoSomething : String; end; implementation
method HelloMessage.DoSomething : String; begin exit 'hello'; end; |
Chrome-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
| uses System.Collections.Generic; type MessageContext = public class public property Item[messageId : String] : IMessage read MessagesById[messageId]; default;
method RegisterMessage<T>(messageId : String); where T is IMessage, T has constructor;
method RegisterMessage<T>(message : T); where T is IMessage; method RegisterMessagesFromAssembly(assemblyRef : System.Reflection.Assembly); private method RegisterMessage(messageId : String; message : IMessage);
MessagesById : Dictionary<String, IMessage> := new Dictionary<String, IMessage>(); readonly; end; implementation
method MessageContext.RegisterMessage<T>(messageId : String); begin RegisterMessage(messageId, new T()); end;
method MessageContext.RegisterMessage<T>(message : T); begin RegisterMessage(message.MessageId, message); end;
method MessageContext.RegisterMessage(messageId : String; message : IMessage); begin if not assigned(message) then raise new ArgumentNullException('blblablbala...', 'message');
if string.IsNullOrEmpty(messageId) then raise new ArgumentNullException('blblablbala...', 'messageId');
if MessagesById.ContainsKey(messageId) then raise new ArgumentException('Message Id "' + messageId + '" is already blblablabla...', 'messageId'); MessagesById.Add(messageId, message); end;
method MessageContext.RegisterMessagesFromAssembly(assemblyRef : System.Reflection.Assembly); begin var messageType := typeof(IMessage);
for clrType in assemblyRef.GetExportedTypes() do begin if not clrType.IsAbstract and messageType.IsAssignableFrom(clrType) then with message := Activator.CreateInstance(clrType) as IMessage do RegisterMessage(message.MessageId, message); end; end; |
Zur Pflicht der (Re-)Implementierung der Property:
Geht nicht!
Du kannst nicht wirklich prüfen, ob eine Klasse wirklich ihre eigene Version der Eigenschaft mitbringt.
OK, du könntest per Reflection prüfen, was der Declaring type der Property ist, aber das wäre schon arg krank. :shock:
Gehe einfach davon aus, dass derjenige, der solche Messages implementiert auch will, dass sie funktionieren. ;-)
BLJ - Do 24.05.07 17:31
oh... danke für deine Mühe!
interessanter Weg. Ich muss zwar zugeben, dass ich etwas Mühe habe den Code zu lesen. Dünkt mich ein seltsames Konstrukt..
hab ja schon Visual Basic (+Script), C#, Java, C, C++, Javascript gesehen aber sowas...? nö...
Allerdings muss ich sagen, dass das schon ein ganz schön grosses Stück code für so eine einfache Funktionalität ist!
bezgl. Skalierbarkeit statische Variablen:
haben statische Variablen einen merkbaren negativen Performance-Einfluss?
Moderiert von
Christian S.: Weitere Fragen entfernt
Robert_G - Do 24.05.07 17:47
BLJ hat folgendes geschrieben: |
oh... danke für deine Mühe!
interessanter Weg. Ich muss zwar zugeben, dass ich etwas Mühe habe den Code zu lesen. Dünkt mich ein seltsames Konstrukt..
hab ja schon Visual Basic (+Script), C#, Java, C, C++, Javascript gesehen aber sowas...? nö... |
Lol! Sorry hatte gerade keine Lust auf C#. ;-)
Zitat: |
Allerdings muss ich sagen, dass das schon ein ganz schön grosses Stück code für so eine einfache Funktionalität ist! |
Eigentlich nicht, den Großteil schreibt ja die IDE für einen. :mrgreen:
Zitat: |
bezgl. Skalierbarkeit statische Variablen:
haben statische Variablen einen merkbaren negativen Performance-Einfluss? |
Nein, aber sie existieren nur einmal pro AppDomain.
Das heißt du kannst dich ganz schön schnell selbst in den Fuß schießen, falls du mal 2 davon auf einmal brauchst. ;-)
Zitat: |
leider habe ich im Moment andere (grössere) Probleme... |
Neue/Andere Frage, neuer Thread.
Das geht sonst a) drunter und drüber und b) wird sich ein potentieller Helfer von meinem Schnipsel obendrüber abgeschreckt fühlen, bevor er deine VS-Frage sieht. :mrgreen:
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!