Wo sind die Limits von C#?
Bsp.:
z.B. ist es nicht ohne weiteres möglich DLL-Funktionen von CSharp für mit VS 6.0 C++ erstellte Programme zu exportieren. (Stichwort vtable entry manuell ergänzen in IL-Code)
Es ist nicht ohne weiteres möglich bei (generischen) Listen für Add und Remove Events auszulösen.
Es ist nicht möglich Attribute ohne Reflection zur Ausführung zu bringen, in dem Sinne, wie es z.B. PostSharp ermöglicht.
Es kann kein Code zur Laufzeit/Compilezeit verändert werden und damit die Assembly zur Laufzeit verändert werden.
Keine Mehrfachvererbung im Sinne von C++
Nachgeladene Assemblies können nicht entladen werden (mal abgesehen über den Ausweg von AppDomain)
Welche Features fehlen euch?
Egal ob diese in Richtung der genannten Beispiele gehen oder nicht.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Es kann kein Code zur Laufzeit/Compilezeit verändert werden.
Was meinst du damit? Klaro kannst du während des Debuggens Code ändern und danach weiterlaufen lassen.
Achtung! - Hinter dir ist ein dreiköpfiger Affe!
Ich meine so etwas in der Art:
LoadAssembly (...);
myClass = Type.GetType (...)
foreach (Method m in myClass) {
InsertStatement (...) //new Code goes here
}
SaveAssembly (...);
Assemblies zur Laufzeit verändern.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Du kannst aber Assemblies zur Laufzeit erzeugen. Also komplett im Hauptspeicher aufbauen, dort übersetzen und direkt laufen lassen.
@Rainbird:
das hatte ich auch ja selbst schon in
Objekte an Laufzeit kompilierten Code übergeben oder auslesen (allgemeine Kommunikation)
beschrieben,
es ist aber nicht möglich, im Enhancer-Sinne (s. dazu [gelöst] Event auf Methoden-Aufruf über Attribute)
Code zur Laufzeit/Compilezeit mit Boardmitteln von C# zu verändern,
auch bezogen auf die eigene Assembly in der man sich gerade befindet.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Wenn man sich von vornherein auf eine Lösung versteift, wird man nie eine
anderen Lösungsweg akzeptieren.
Hast Du dir schon mal DynamicMethod angeschaut?
Damit kannst Du relativ einfach ILCode zur Laufzeit erzeugen.
Wenn Du da genauso viel energie hineinsetzt wie in deinen Enhancer hast Du
eine vergleichbare lösung.
Du kannst auch mit Linq code generieren und compilieren, und......
Wie heist es immer so schön, viele Wege führen nach Rom ( aber wer will da schon hin 😉
Die meisten deiner genannten Merkmale sind aber nicht C# spezifisch sondern gründen in .Net.
Zum Beispiel das Entladen der Assemblies, die nichtvorhandene Mehrfachvererbung, die Änderung vorhandenen Codes zur Laufzeit usw.
Das wird nicht durch C# sondern durch die CLI und das CTS vorgeschrieben.
Genauso das Auslösen der Events bei den Collections, das liegt wiederum in der BCL und nicht in C# 🙂
Es ist wirklich schwer reine Merkmale von C# aufzulisten, aber es gab mal nen Thread hier dazu wo es vor allem um die fehlende Transparenz bei den Typen ging(bei Verwendung von Variablen nicht erkennbar ob es Werte oder Referenztypen sind, bei C++ z.b. leicht erkennbar anhand ob nun nen *, & bzw. . oder -> benutzt wird), und auch Properties die nicht als solche erkannt werden und Fehler provozieren können.
Baka wa shinanakya naoranai.
Mein XING Profil.
Ok, noch mal zur Klarstellung:
Ich wollte gar keine Gegenbeispiele zu meinen Beispielen, ich wollte wissen wo liegen für EUCH die Limits in C-Sharp?
Was habt ihr euch schon oft gewünscht, was mit C-Sharp nicht möglich ist oder was ihr nicht hinbekommt?
Vielleicht hätte ich die Formulierung auch einfach so machen sollen:
Was wünscht ihr euch für die C# Spezifikation 4.0?
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Praktisch alle Features von C&Omega ; 😃 Okay, der Datenzugriff wurde in Form von Linq schon eingebaut, aber die asynchronen Methoden und Streams sind auch klasse.
Baka wa shinanakya naoranai.
Mein XING Profil.
Wenn Du dir die möglichkeiten von der 3.5 anschaust, und speziell etwas wie
Jasper siehst, dann wünsche ich mir das schon lange in VB.NET und IronPython
mögliche LateBinding.
Wenns geht mit einem Schlüsselwort, und ständigem nicht abschaltbaren
gemecker vom Compiler, damit es nicht zur gewohnheit wird 😉
Hallo dr4g0n76,
von dem, was du gesagt hast, stören mich eigentlich nur diese beiden Punkte:
Es ist nicht ohne weiteres möglich bei (generischen) Listen für Add und Remove Events auszulösen.
Es ist nicht möglich Attribute ohne Reflection zur Ausführung zu bringen, in dem Sinne, wie es z.B. PostSharp ermöglicht.
Wobei mich eigentlich nicht stört, dass man Reflection benutzen muss. Mich stört eher, dass man in einer Methode/Propertie nicht einfach sagen kann: Gib mir alle "meine" Attribute.
Und der Punkt mit Add/Remove ist eher eine Folge einer allgemeineren Schwäche von C#:
Ich weiß zwar auch, warum das so ist, aber ich denke, die Vorteile würden überwiegen, wenn alle Methoden virtual wären.
Dann gibt es noch eine Kleinigkeit, die mich aber nicht wirklich stört. Eher einer kleine Unebenheit der Sprache:
Dich könnte auch noch Schwächen der C#-Sprache interessieren.
herbivore
Original von dr4g0n76
Was habt ihr euch schon oft gewünscht, was mit C-Sharp nicht möglich ist oder was ihr nicht hinbekommt?
Na ja, die Überladung einer Methode nur durch ihren Rückgabewert wäre manchmal sehr praktisch.
Das also so etwas realisierbar wäre:
decimal Multiplizieren(decimal d1, decimal d2)
{
return d1 * d2;
}
double Multiplizieren(decimal d1, decimal d2)
{
return Convert.ToDouble(d1 * d2);
}
Hallo winSharp93,
Dass das nicht geht kann ich gut nachvollziehen! Es würde viel zu viele Probleme mit sich bringen, weil es gibt endlose Situationen, in denen nicht klar entschieden werden kann, welche "Überladung" genommen werden soll. Ein simples Beispiel:
decimal Multiplizieren(decimal d1, decimal d2)
{
return d1 * d2;
}
double Multiplizieren(decimal d1, decimal d2)
{
return Convert.ToDouble(d1 * d2);
}
Aufruf:
object myVar = Multiplizieren(dec1, dec2);
Ich hoffe du kannst nachvollziehen, warum es dieses "Feature" nicht gibt.
Gruß,
Thomas
A wise man can learn more from a foolish question than a fool can learn from a wise answer!
Bruce Lee
Populanten von Domizilen mit fragiler, transparenter Außenstruktur sollten sich von der Translation von gegen Deformierung resistenter Materie distanzieren!
Wer im Glashaus sitzt, sollte nicht mit Steinen werfen.
Hallo progger,
naja, ich finde eher das Argument, dass man den Rückgabewert gar nicht übernehmen muss, bzw. dass durch das Überladen von Rückgabewerten das Übernehmen des Rückgabewerts erzwungen werden würde.
Denn das nicht Eindeutigkeitsproblem hat man ja auch beim Überladen von Parametern (ohne dass deshalb das Überladen von Parametern verboten wäre):
decimal Multiplizieren(decimal d1, decimal d2) ...
double Multiplizieren(double d1, double d2) ...
Multiplizieren (1, 1);
error CS0121: Der Aufruf unterscheidet nicht eindeutig zwischen folgenden Methoden und Eigenschaften: Bsp.Multiplizieren(decimal, decimal) und Bsp.Multiplizieren(double, double).
herbivore
Ich hätte mir schon mal etwas ähnliches gewünscht: Das Überschreiben (nicht überladen) mit einem Rückgabe-Typ der vom vorherigen Rückgabe-Typ ableitet:
class A {}
class B : A {}
class X
{
public virtual A Foo()
{ ... }
}
class Y : X
{
public override B Foo()
{ ... }
}
Wobei B zwingend von A erben muss. Afaik gibt es OO Sprachen die das unterstützen.
Das mit dem Überladen von Funktionen find ich nicht ganz so tragisch. Man muss sich nur ein paar "neue" Namen einfallen lassen.
public double ToDouble(...)
public int ToDouble(...)
Reizen würde mich eher, das die Mehrfachvererbung ähnlich C++
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Was mir bei C# fehlt sind statische lokale Variablen wie z.B. in C und C++.
int GetNextNumber() {
static int val = 0;
if (val > 1024)
val = 0;
return val++;
}
Hallo marsgk,
bis auf die größere Sichtbarkeit entsprechen Klassenvariablen dem, was du willst.
herbivore
Naja, ich will ja nix sagen, aber auch statische lokale Variablen gibts bei VB.NET, die sind im IL-Code auch als Klassenvariablen implementiert. Wenn ich eine statische Integer-Variable mit dem Namen i in einer Methode Test anlege, dann erzeugt VB automatisch die Klassenvariable $STATIC$2001$Test$i, die im IL-Code mit dem Modifikator specialname ausgestattet ist.
Hallo onlinegurke,
da der Thread aber "Limits von C# / CSharp" und nicht "Features von VB / VisualBasic" heißt, ändert es nichts an dem Limit von C#, wenn es das Feature in VB gibt. 🙂
herbivore
Die Aussage sollte sein, dass das vermeintliche Feature von anderen Sprachen, statische lokale Variablen anlegen zu können (z.B. eben VB.NET), nur eine reine Compilezeitgeschichte ist, und damit in meinen Augen nicht wirklich ein Limit...
Was mich an C# stört ist aber die Uneindeutigkeit von { und }, weil das das Parsen von Quelltext sehr erschwert...
Hallo onlinegurke,
ja, aber VB sorgt dann dafür, dass obwohl es intern eine Klassenvariable benutzt, auf diese nur aus der jeweiligen Methode zugegriffen werden kann. Wenn man in C# "von Hand" eine Klassenvariable benutzt, muss man darauf selber aufpassen. Insofern ist es schon ein kleines Limit (im Sinne von Schwäche) von C#, wenn der Compiler keine lokalen statischen Variablen unterstützt.
Was meinst du mit Uneindeutigkeit?
herbivore
Ich persönlich finde die Generics nicht ganz überzeugend. Diese komische Zwitterverhalten (Compile- vs. Laufzeit) ist manchmal sehr lästig - auch wenn mir klar ist, dass es da nix zu verbessern gibt, ohne .NET komplett umzukrempeln.
@herbivore
{ und } können das Ende eines beliebigen Codeabschnitts sein, also von
Ich hab vor einiger Zeit ja mal ein Progrämmchen programmiert um bestehenden Quellcode zu sortieren, da ging's dann im Parser drum zu erkennen, was der gerade eingelesene Code nun darstellt, um z.B. die Eigenschaften zu sortieren und auszulagern. Eine nicht funktionierende Vorversion davon für VB.NET (das sagt einem ja, welcher Codeabschnitt gerade beendet wird) steht auch irgendwo unter Projekte. Bei C# ist sowas aber viel aufwändiger, weil man die ganze Zeit die { und } mitzählen muss (außerdem ist eine Felddefinition nicht wirklich erkennbar)
Original von herbivore
Hallo marsgk,bis auf die größere Sichtbarkeit entsprechen Klassenvariablen dem, was du willst.
herbivore
Und genau auf die Sichtbarkeitsunterschiede kommt es mir auch an 😄. Ich dachte mit meinem Beispiel kann ich das etwas verdeutlichen. Öfters brauche ich eine Variable nur in einer Funktion, dafür aber "statisch". Diese Variable als Membervariable zu deklarieren ist unübersichtlicher.
Original von onlinegurke
@herbivore{ und } können das Ende eines beliebigen Codeabschnitts sein, also von
- einer Klassendefinition
- einer Methodendeklaration
- einer Struktur
- einer Enumeration
- einer Eigenschaft
- einer Get-Deklaration
- einer Set-Deklaration
...
u.v.m.Ich hab vor einiger Zeit ja mal ein Progrämmchen programmiert um bestehenden Quellcode zu sortieren, da ging's dann im Parser drum zu erkennen, was der gerade eingelesene Code nun darstellt, um z.B. die Eigenschaften zu sortieren und auszulagern. Eine nicht funktionierende Vorversion davon für VB.NET (das sagt einem ja, welcher Codeabschnitt gerade beendet wird) steht auch irgendwo unter Projekte. Bei C# ist sowas aber viel aufwändiger, weil man die ganze Zeit die { und } mitzählen muss (außerdem ist eine Felddefinition nicht wirklich erkennbar)
Mit Xml kannst du auch viele geschachtelte Sachen auslesen. Ich finde das ist nicht so das große Problem.
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
die schlimmste sünde in c# ist die unmäßige verwendung des sealed keywords...
meinetwegen kann man das keyword ganz streichen...
ausserdem schließ ich mich herbivore an mit:
loop:
btst #6,$bfe001
bne.s loop
rts
Generics haben tatsächlich noch einige Schwächen, vor allem in den Constraints. Was zum Beispiel fehlt:
Was mir sonst noch einfällt:
Indizierte Properties (außer this), VB und C++/CLI können es nämlich:
Also etwa:
public class Foo {
List<string> wörter;
List<int> zahlen;
public string Wörter[int index] {
get { return wörter[index]; }
}
public int Zahlen[int index] {
get { return zahlen[index]; }
}
}
Eine der größten Schwächen in der BCL ist meiner Meinung nach die sehr schwache Collections-Bibliothek. Zum einen unvollständig, zum anderen würde ich mir eine stärkere Aufspaltung zwischen lesenden und schreiben Funktionen wünschen. ICollection hat z.B. immer eine Add/Remove/Clear-Methode, auch wenn die Collection Schreibgeschützt ist. Ich fände es besser, wenn alle lesenden Eigenschaften und Methoden in ein eigenes Interface ICollectionView oder so fließen würden und ICollection dann von ICollectionView erbt und Add/Remove/Clear zufügt. Dadurch könnte man schon zur Compilezeit die Nur-Lesbarkeit einer Collection ausdrücken, indem man dem client nur ein ICollectionView-Objekt zur Verfügung stellt. Entsprechendes müsste dann auch mit IList und IDictionary gemacht werden. Ich sehe allerdings ein, dass das die Anzahl der Interfaces und Klassen drastisch erhöhen würde. Ist halt ein Trade-Off zwischen Funktionalität und Übersicht.
Grüße,
Andre
Original von VizOne
Indizierte Properties (außer this), VB und C++/CLI können es nämlich:
Full ack. Statt der blöden Indexer wären mir parametrisierbare Properties auch viel lieber gewesen.
Operatorüberladung (Speziell die Castingoperatoren) für Schnittstellen hätt ich gern noch... 🙂
am allerschwerwiegendsten überhaupt finde ich das Fehlen des const-Schlüsselwortes, wie man es von C++ her kennt. Ich meine damit nicht konstante Variablen (denn die gibt es), sondern dass man Funktionen als konstant deklarieren kann und konstante Parameter festlegen kann. Das würde etliche Tipparbeit ersparen (z.B. muss man nicht für jeden Sch*** "immutable Types / Interfaces erstellen).
als nächstes wäre Mehrfachvererbung nett, aber das ist ja bekanntlich Geschmackssache 🙂
und last, but not least, worüber ich vor kurzem gestoßen bin:
man kann keine generischen Properties erstellen:
public T SomeProp<T>
{
get { ... }
}
schade, hätte ich gebraucht. Aber ist nicht so schlimm, es ist jetzt halt eine Get-Funktion
Hallo steven11,
am allerschwerwiegendsten überhaupt finde ich das Fehlen des const-Schlüsselwortes, wie man es von C++ her kennt. Ich meine damit nicht konstante Variablen (denn die gibt es), sondern dass man Funktionen als konstant deklarieren kann und konstante Parameter festlegen kann.
Siehe Konstante Parameter
man kann keine generischen Properties erstellen:
Kann man schon, nur kann man den Typparameter nicht direkt bei der Property angeben. So geht es:
public class SomeClass<T>
{
public T SomeProp
{
get { return default (T); }
}
}
herbivore
Hallo zusammen,
ich finde es in C# sehr doof, dass man beim Auslösen von Events immer zunächst auf NULL überprüfen muss. In diesem Zusammenhang finde ich persönlich das Registrieren und Deregistrieren irgendwie unhandlich und kann bei falscher Anwendung zu Speicherlecks führen.
Ich finde es unpraktisch, dass man in GUI Anwendungen und mehreren Threads immer InvokeRequired abfragen muss (das hätte man auch automatisch implementieren können).
Ich finde es unpraktisch dass im .NET Framework 1.1 und 2.0 die ganzen GUI Controls nicht richtig Objektorientiert programmiert sind (z.B. TextBox oder ScrollBar). [hat jetzt nichts mit C# direkt zu tun und ist mit 3.0 und dem WPF wahrscheinlich hinfällig].
Ansonsten ist C# doch sehr nett 😉
Gruß
Norman-Timo
A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”
If you declare a method that takes a non-const Bla, you can't pass it a const Bla. So now you're stuck. So you gradually need a const version of everything that isn't const, and you end up with a shadow world.
diese Auffassung kann ich nicht teilen, denn man deklariert einen Funktionsparameter nur dann als nicht-const, wenn man das Objekt verändern möchte, also nicht-const Funktionen aufrufen möchte. Mir ist klar, dass es bei Interfaces nicht immer leicht ist, das zu entscheiden - es kommt aber letztlich auf gutes Klassendesign an, dann passt das 😉
Zur Property:
genau das war in meinem speziellen Fall nicht möglich, weil es sich um ein Interface handelt, das die generische Property enthält
Hallo steven11,
... denn man deklariert ...
das ist doch genau das Problem. const-Parameter funktionieren nur, wenn sich wirklich alle und immer daran halten, Parameter, die sie nicht verändern, als const zu deklarieren. Und das ist eben in der Praxis nicht der Fall. Und schon wenn sich einer (z.B. ein Dritthersteller) nicht daran hält, läuft man auf Probleme. const ist etwas für die ideale Welt (oder ein kleines abgeschottetes Paradies), nicht für die reale Welt.
herbivore
ok, ein bisschen ist was dran. Ich vermisse es trotzdem 🙂
Original von steven11
Das würde etliche Tipparbeit ersparen (z.B. muss man nicht für jeden Sch*** "immutable Types / Interfaces erstellen).
Naja. Die "Schattenwelt" ist ja durchaus real. Nicht bei allen Funktionen ist klar, ob const oder nicht. Nimm mal ToString(). Falls solche Funktionen noch mehr Parameter haben und alle const oder nicht sein können, landest du bei einer schöner Permutation von Parameterarten. Spätestens dann verläßt es selbst die diszipliniertesten Const-Coder und es wird gecastet. Zudem: Welche Objekte sind denn wirklich const? Zu 90% strings....
das ist imho kein argument: die meisten funktionen benötigen nur const-parameter, weil sie nur irgendwelche informationen aus den objekten auslesen. warum sollte man dann eine nicht-const variante anbieten?
das ist ja gerade der vorteil von const. wenn kein const angegeben wurde, sieht man auf den ersten blick, dass das objekt geändert wird
Bei ausschließlich selbst geschreibenem Code mag das angehen. Ansonsten ist das einfach trügerisch. Du verläßt dich auf den const im Parameter. Wenn aber nicht alle entsprechenden Methoden der Klasse sauber als const ausgezeichnet sind, kannst du ein Objekt über diese Methoden verändern trotz const. Bei immutable kann das eben nicht passieren. Aber ich hab lange genug C++ programmiert um zu wissen, dass jeder C-Coder dankbar für jeden Zucker ist, dem der Compiler einen bietet, und sei es noch so unvollkommen. 🙂 In C# hab ich const noch nie vermißt.
Original von dr4g0n76
Es ist nicht ohne weiteres möglich bei (generischen) Listen für Add und Remove Events auszulösen.
Kann man sich den Listentyp nicht ableiten und einfach die Add-/Remove-Methoden mit solchen überschreiben, die den Aufruf an die Basisklasse weiterreichen und dabei ein Ereignis auslösen? Oder meintest du das mit "nicht ohne weiteres"? Oder bin ich jetzt nur zu blauäugig und dieses Vorgehen wäre in der Praxis nicht machbar oder zu kompliziert?
So schwer ist das mit den Events auch wieder nicht.
Einfach von CollectionBase bzw. Collection<T> ableiten und in den entsprechenden protected Methoden den Event auslösen.
Geht viel einfacher.
Das Interface IList<T> einbinden und implementieren.
Da List<T> ja schon alles implementiert, braucht man dann nur die
routinen "neu" implementieren, die auch wirklich benötigt werden.
public class myList : List<string>, IList<string>
{
#region IList<string> Members
void IList<string>.Insert(int index, string item)
{
}
void IList<string>.RemoveAt(int index)
{
}
#endregion
#region ICollection<string> Members
void ICollection<string>.Add(string item)
{
}
void ICollection<string>.Clear()
{
}
bool ICollection<string>.Remove(string item)
{
}
#endregion
}
Original von FZelle
Geht viel einfacher.Das Interface IList<T> einbinden und implementieren.
Da List<T> ja schon alles implementiert, braucht man dann nur die
routinen "neu" implementieren, die auch wirklich benötigt werden.public class myList : List<string>, IList<string> { // [gekürzt] }
dann muss man aber aufpassen, dass man nicht aus versehen oder schreibfaulheit den typ myList nach aussen gibt, sondern immer nur IList, da die explizit implementierten methoden nur aufgerufen werden, wenn man übers interface zugreift. über myList.xyz() würden die methoden von List aufgerufen werden, was man in dem fall wahrscheinlich nicht wollen würde.
loop:
btst #6,$bfe001
bne.s loop
rts
Original von FZelle
Geht viel einfacher.
Das Interface IList<T> einbinden und implementieren.
Naja wenn du meinst...
Ich finde es fehleranfällig und umständlich alle Methoden erneut zu implementieren.
was man noch machen kann ist nur IList<> implementieren, und in allen methoden virtual auf eine private echte List<> umleiten:
public class VirtualList : IList<string>
{
private List<string> theList = new List<string>();
public virtual void virtual Add(string item)
{
theList.Add(item);
}
// den rest auch implementieren.
}
dann kann man entweder gleich in den methoden einen event auslösen oder sonst was machen - oder von dieser VirtualList ableiten, nur noch das Add() überschreiben und dort den event feuern.
von Collection<> abzuleiten, und übschreiben was nötig ist, halt ich inzwischen aber für die bessere lösung. ist auch weniger arbeit.
loop:
btst #6,$bfe001
bne.s loop
rts
@0815Coder
Genau das macht doch schon Collection<T>.
Warum alles neu erfinden? Wenn du von Collection<T> erbst, gibt es 4 Methoden(Insert,Remove, Clear, Set) die du überschreiben kannst und dort deinen event feuern kannst. Einfacher gehts wirklich nicht mehr.
stimmt, Collection<T> verwendet intern eine List<T>
aber was ich an sich zeigen wollte war, wie es möglich ist, klassen die nicht oder "nicht genug" virtuell sind, zu virtualisieren.
obs immer sinn macht sei dahingestellt.
loop:
btst #6,$bfe001
bne.s loop
rts