Was sind einige der größten Designfehler in C # oder .NET Framework im Allgemeinen?
Beispiel: Es gibt keinen nicht nullbaren Zeichenfolgentyp und Sie müssen beim Abrufen von Werten aus einem IDataReader nach DBNull suchen.
Was sind einige der größten Designfehler in C # oder .NET Framework im Allgemeinen?
Beispiel: Es gibt keinen nicht nullbaren Zeichenfolgentyp und Sie müssen beim Abrufen von Werten aus einem IDataReader nach DBNull suchen.
Antworten:
Ich stimme diesem Beitrag nachdrücklich zu (für diejenigen, die das Fehlen von ToString vermasseln, gibt es ein Debugger-Attribut, um ein benutzerdefiniertes Format für Ihre Klasse bereitzustellen).
Zusätzlich zu der obigen Liste möchte ich die folgenden angemessenen Anforderungen hinzufügen:
T : new(string)oder woT : new(string, int)var e = new Foo(); e { Bar = baz };Either<T>" jedoch nicht. Daher würde ich gerne einen geschlossenen algebraischen Typ deklarieren und einen umfassenden Mustervergleich erzwingen (im Grunde erstklassige Unterstützung für das Besuchermuster, aber weitaus effizienter); Nehmen Sie einfach Aufzählungen, erweitern Sie sie mit umfassender Unterstützung für den Mustervergleich und lassen Sie keine ungültigen Fälle zu.System.IOKlassen Streametwas schlecht gestaltet sind; Jede Schnittstelle, für deren Ausführung einige Implementierungen erforderlich sind, NotSupportedExceptionist ein schlechtes Design.IListsollte viel einfacher sein als es ist; in der Tat kann dies für viele der konkreten Sammlungsschnittstellen zutreffen, wie z ICollection.INotifyPropertyChanged, die den Feldnamen als Zeichenfolge verwenden , sicher zu reflektieren ; Sie können dies tun, indem Sie eine Erweiterungsmethode verwenden, die ein Lambda mit a MemberExpression, dh, verwendet. () => Foo, aber das ist nicht sehr effizient,
nameof()Operator für einzelne Mitgliedsnamen hinzugefügt , funktioniert jedoch nicht in Generika ( nameof(T) == "T"anstelle des tatsächlichen Namens des Typarguments: Sie müssen dies noch tun typeof(T).Name). Außerdem können Sie keine "Pfad" -String abrufen , z. B. nameof(this.ComplexProperty.Value) == "Value"Einschränkung seiner möglichen Anwendungen.IArithmetic; andere nützliche gemeinsam genutzte Bedienerschnittstellen sind ebenfalls möglich,readonlySchlüsselwort hatte und C # 6.0 schreibgeschützte automatische Eigenschaften hinzufügte, ist es nicht so streng wie die echte Sprachunterstützung für unveränderliche Typen und Werte.Das reicht wohl erstmal. Dies sind alles Irritationen, auf die ich in der letzten Woche gestoßen bin. Ich könnte wahrscheinlich stundenlang weitermachen, wenn ich mich wirklich darauf konzentrieren würde. C # 4.0 fügt bereits benannte, optionale und Standardargumente hinzu, die ich ausdrücklich befürworte.
Nun zu einer unvernünftigen Bitte:
Bitte schön? :-)
List<T>eine Million Ts. Wie schlagen Sie vor, dass der Schnappschuss effizient aufgenommen wird? # 21: Verwenden Sie das readonlySchlüsselwort ... obwohl es hier einige gute Vorschläge gibt, sind es meistens nur diese - Vorschläge, keine Designfehler.
Reset()Methode IEnumerator<T>war ein Fehler (für Iteratorblöcke verlangt die Sprachspezifikation sogar , dass dies eine Ausnahme auslöst)IEnumerable<out T>und Func<in T, out TResult>, aber keine konkreten Typen (wie List<T>)) Unterstützung für Kovarianten / Kontravarianzen hinzugefügt .ApplicationException eher in Ungnade gefallen - war das ein Fehler?ContainsAddSystem.Collections.ConcurrentTypen , mit TryAdd, GetOrAdd, TryRemove, etc wurden in .NET Framework 4.0 hinzugefügt - obwohl Methoden , die eine Fabrik Delegierten nehmen nicht die Fabrik Garantie wird nur einmal pro Taste aufgerufen werden.using/ lockpattern hätte besser genutzt werden können - vielleicht könnten sie eine wiederverwendbare (erweiterbare?) Syntax verwenden; Sie können dies simulieren, indem Sie zurückkehren IDisposableund verwenden using, aber es hätte klarer sein könnenFoo(SqlConnection! connection)(die einen Null-Check / einfügt throw) wäre schön (im Gegensatz zu int?etc)
dynamic, oder Sie können es ermöglichen , wie diesforeachErweiterung deklariert , was bedeutet, dass anon-Methods / Lambdas die einzelne Variable erfassen und nicht eine pro Iteration (schmerzhaft beim Threading / async / etc).
ApplicationExceptionsei ein Fehler - nicht nützlich, wie sie gehofft hatten. Sie sagten auch, das System.Exceptionhätte sein sollen abstract.
TextWriter ist eine Basisklasse von StreamWriter. wtf?
Das verwirrt mich immer bis zum Äußersten.
Ein kleiner C # pet peev - Konstruktor verwendet die C ++ / Java-Syntax, bei der der Konstruktor den gleichen Namen wie die Klasse hat.
New()oder ctor()wäre viel schöner gewesen.
Tools wie Coderush machen dies zwar weniger zu einem Problem beim Umbenennen von Klassen, aber New () bietet aus Gründen der Lesbarkeit eine große Klarheit.
class Foo { new(int j) {i = j} int i; }
NewGroßbuchstaben sind gegen die Konvention), zögere ich, es als Designfehler zu bezeichnen. Sie wollten bestehende C ++ / Java-Entwickler gewinnen, und das Ausleihen vieler dummer alter syntaktischer Konventionen half ihnen wohl dabei, ihr Ziel zu erreichen.
Ich verstehe nicht, dass du es nicht kannst
wo T: neu (U)
Sie deklarieren also, dass der generische Typ T einen nicht standardmäßigen Konstruktor hat.
bearbeiten:
Ich möchte das machen:
public class A
{
public A(string text)
{
}
}
public class Gen<T> where T : new(string text)
{
}
Ich bin wirklich überrascht, dass ich als erster diesen erwähne:
ADO.NET-typisierte Datensätze machen nullfähige Spalten nicht als Eigenschaften nullbarer Typen verfügbar. Sie sollten in der Lage sein, dies zu schreiben:
int? i = myRec.Field;
myRec.Field = null;
Stattdessen muss man das schreiben, was einfach nur dumm ist:
int? i = (int?)myRec.IsFieldNull() ? (int?)null : myRec.Field;
myRec.SetFieldNull();
Dies war in .NET 2.0 ärgerlich, und es ist jetzt noch ärgerlicher, dass Sie in Ihren netten, ordentlichen LINQ-Abfragen Jiggery-Pokery wie oben verwenden müssen.
Es ist auch ärgerlich, dass die generierte Add<TableName>RowMethode für den Begriff der nullbaren Typen ähnlich unempfindlich ist. Dies gilt umso mehr, als die generierten TableAdapterMethoden dies nicht tun .
In .NET gibt es nicht viel, was mir das Gefühl gibt, dass das Entwicklerteam sagte: "Okay, Jungs, wir sind nah genug dran - versenden Sie es!" Aber das tut es sicher.
DBNull.Value, wenn nuller für die Darstellung von NULL vollkommen ausreichend gewesen wäre. Glücklicherweise verwendet LINQ-to-SQL nur null für NULL.
Bearbeiten
5. Ein weiteres Ärgernis von mir ist, wie System.Reflection.BindingFlags je nach verwendeter Methode unterschiedliche Verwendungszwecke hat. Was bedeutet beispielsweise in FindFields CreateInstance oder SetField? Dies ist ein Fall, in dem sie die Bedeutung hinter dieser Aufzählung überladen haben, was verwirrend ist.
Ich weiß nicht, dass ich sagen würde, dass es sich um einen Designfehler handelt, aber es wäre wirklich schön, wenn Sie einen Lambda-Ausdruck auf die gleiche Weise wie in VB ableiten könnten:
VB:
Dim a = Function(x) x * (x - 1)
C #
Es wäre schön, wenn dies möglich wäre:
var a = x => x * (x - 1);
Anstatt dies tun zu müssen:
Func<int, int> a = x => x * (x - 1);
Mir ist klar, dass es nicht mehr lange dauert, aber im Code Golf zählt jeder Charakter verdammt! Berücksichtigen sie das nicht, wenn sie diese Programmiersprachen entwerfen? :) :)
(int x) => x * (x -1);kann bedeuten Func<int, int>oder es kann bedeutenExpression<Func<int, int>>
+nicht für definiert ist object.
Die System.Object- Klasse:
Equals und GetHashCode - nicht alle Klassen sind vergleichbar oder hashbar, sollten auf eine Schnittstelle verschoben werden. IEquatable oder IComparable (oder ähnliches) fällt mir ein.
ToString - Nicht alle Klassen können in eine Zeichenfolge konvertiert werden. Sie sollten in eine Schnittstelle verschoben werden. IFormattable (oder ähnliches) fällt mir ein.
Die ICollection.SyncRoot- Eigenschaft:
Generika sollten von Anfang an dabei gewesen sein:
EqualityComparer<T>.Defaultkorrektes Update . Dann beide var dict = new Dictionary<object, string>(EqualityComparer<object>.Default)und var dict = new Dictionary<object, string>()verwenden Referenzvergleich / Gleichheit.
EqualityComparer<T>.Defaulttut. Sie müssen nicht bei jeder Suche nachsehen. Der Vergleicher ist eine Eigenschaft für die DictionaryInstanz, und jeder Dictionaryweiß, welche er verwendet.
Eines der Dinge, die mich irritieren, ist das Predicate<T> != Func<T, bool>Paradoxon. Sie sind beide Delegierte des Typs T -> boolund dennoch nicht zuweisungskompatibel.
Einige Leute (ISVs) wünschen sich, dass Sie es zur Erstellungszeit zu Maschinencode kompilieren und verknüpfen können, um eine native ausführbare Datei zu erstellen, die die dotNet-Laufzeit nicht benötigt.
Wir wissen so viel über die richtigen OO-Techniken. Entkopplung, vertragliche Programmierung, Vermeidung unzulässiger Vererbung, angemessene Verwendung von Ausnahmen, offenes / geschlossenes Prinzip, Liskov-Substituierbarkeit usw. In den .Net-Frameworks werden noch keine Best Practices verwendet.
Für mich liegt der größte Fehler im Design von .Net nicht auf den Schultern von Riesen. Förderung weniger als idealer Programmierparadigmen für die Masse der Programmierer, die ihre Frameworks verwenden .
Wenn MS dies beachtet hätte, hätte die Welt der Softwareentwicklung in diesem Jahrzehnt große Fortschritte in Bezug auf Qualität, Stabilität und Skalierbarkeit machen können, aber leider scheint sie rückläufig zu sein.
Ich mag die C # switch-Anweisung nicht.
Ich hätte gerne so etwas
switch (a) {
1 : do_something;
2 : do_something_else;
3,4 : do_something_different;
else : do_something_weird;
}
Also keine Pausen mehr (leicht zu vergessen) und die Möglichkeit, verschiedene Werte durch Kommas zu trennen.
switchist grundsätzlich in allen Sprachen kaputt, die die absichtlich verkrüppelte Version von C emulieren (optimiert für Geschwindigkeit!). VB schneidet viel besser ab, liegt aber immer noch Lichtjahre hinter Sprachen mit Mustervergleich (Haskell, F #…).
Ereignisse in C #, bei denen Sie explizit nach Listenern suchen müssen. War das nicht der Punkt bei Ereignissen, an jemanden zu senden, der gerade dort war? Auch wenn es keine gibt?
Das schreckliche (und für die meisten Menschen völlig unsichtbare) O (N ^ 2) -Verhalten verschachtelter / rekursiver Iteratoren .
Ich bin ziemlich enttäuscht, dass sie darüber Bescheid wissen und wissen, wie man es behebt, aber es wird nicht als ausreichend priorisiert angesehen, um die Aufnahme zu verdienen.
Ich arbeite die ganze Zeit mit baumartigen Strukturen und muss den Code ansonsten kluger Leute korrigieren, wenn sie auf diese Weise versehentlich sehr teure Operationen einführen.
Das Schöne an "Yield Foreach" ist, dass die einfachere, einfachere Syntax korrekten, performanten Code fördert. Dies ist die "Grube des Erfolgs" , nach der sie meiner Meinung nach streben sollten, bevor sie neue Funktionen für den langfristigen Erfolg der Plattform hinzufügen.
Einige Klassen implementieren Schnittstellen, aber sie implementieren nicht viele der Methoden dieser Schnittstelle, z. B. Array implementiert IList, aber 4 von 9 Methoden lösen NotSupportedException http://msdn.microsoft.com/en-us/library/system.array_members aus .aspx
Statische Elemente und verschachtelte Typen in Schnittstellen.
Dies ist besonders nützlich, wenn ein Schnittstellenmitglied einen Parameter eines Typs hat, der für die Schnittstelle spezifisch ist ( zenum . B. einen ). Es wäre schön, den Aufzählungstyp im Schnittstellentyp zu verschachteln.
Die schrecklich gefährliche Standardnatur von Ereignissen. Die Tatsache, dass Sie ein Ereignis aufrufen können und sich aufgrund des Entfernens von Abonnenten in einem inkonsistenten Zustand befinden, ist einfach schrecklich. Weitere Informationen zu diesem Thema finden Sie in den hervorragenden Artikeln von Jon Skeet und Eric Lippert .
null überall.
const nirgends.
APIs sind inkonsistent, z. B. das Mutieren einer Array-Rückgabe void, das Anhängen an eine StringBufferRückgabe jedoch dieselbe veränderbare StringBuffer.
Sammlungsschnittstellen sind nicht mit unveränderlichen Datenstrukturen kompatibel, z. B. Addin System.Collections.Generic.IList<_>kann kein Ergebnis zurückgeben.
Keine strukturelle Eingabe, also schreiben Sie System.Windows.Media.Effects.SamplingMode.Bilinearstatt nur Bilinear.
Veränderbare IEnumeratorSchnittstelle, die von Klassen implementiert wird, wenn sie unveränderlich sein soll struct.
Gleichheit und Vergleich ist ein einziges Chaos: Sie haben System.IComparableund Equalsaber dann haben Sie auch bekommen System.IComparable<_>, System.IEquatable, System.Collections.IComparer, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.Collections.Generic.IComparerund System.Collections.Generic.IEqualityComparer.
Tupel sollten Strukturen sein, aber Strukturen verhindern unnötig die Eliminierung von Tail Calls, sodass einer der häufigsten und grundlegendsten Datentypen unnötig zugewiesen wird und skalierbare Parallelität zerstört wird.
IEnumerator?
0 Mondschein als Aufzählung
Besonderheiten der Aufzählung: http://blogs.msdn.com/abhinaba/archive/2007/01/09/more-peculiarites-of-enum.aspx
Wie dieses gute Beispiel zeigt: http://plus.kaist.ac.kr/~shoh/postgresql/Npgsql/apidocs/Npgsql.NpgsqlParameterCollection.Add_overload_3.html
Mein Vorschlag, nutzen Sie das "@" - Zeichen:
anstatt:
if ((myVar & MyEnumName.ColorRed)! = 0)
benutze das:
if ((myVar & MyEnumName.ColorRed)! = @ 0)
So ergänzen Sie die lange Liste der guten Punkte, die bereits von anderen gemacht wurden:
DateTime.Now == DateTime.Now in den meisten, aber nicht allen Fällen.
StringWas unveränderlich ist, hat eine Reihe von Optionen für Konstruktion und Manipulation, aber StringBuilder(was veränderlich ist) nicht.
Monitor.Enterund Monitor.Exitsollten Instanzmethoden gewesen sein. Anstatt ein bestimmtes Objekt zum Sperren neu zu erstellen, können Sie ein neues Objekt erstellen Monitorund dieses sperren.
Destruktoren sollten niemals Destruktoren genannt worden sein. Die ECMA-Spezifikation nennt sie Finalizer, was für die C ++ - Menge viel weniger verwirrend ist, aber die Sprachspezifikation bezeichnet sie immer noch als Destruktoren.
DateTime.Noweine ist die offensichtlichste Rennbedingung der Welt, aber +1 für den Rest
Die Art und Weise, wie wir Eigenschaften verwenden, irritiert mich manchmal. Ich stelle sie mir gerne als Äquivalent zu den Methoden getFoo () und setFoo () von Java vor. Aber das sind sie nicht.
Wenn in den Richtlinien zur Verwendung von Eigenschaften festgelegt ist, dass Eigenschaften in beliebiger Reihenfolge festgelegt werden können, damit die Serialisierung funktioniert, sind sie für die Überprüfung der Setterzeit unbrauchbar. Wenn Sie aus einem Hintergrund kommen, in dem Sie verhindern möchten, dass sich ein Objekt jemals in einen ungültigen Zustand versetzt, sind Eigenschaften nicht Ihre Lösung. Manchmal scheitern ich nur um zu sehen , wie sie sind besser als öffentliche Mitglieder, da sind wir so begrenzt , welche Arten von Dingen , die wir sind angeblich in Eigenschaften zu tun.
Zu diesem Zweck habe ich mir immer gewünscht (das wird hier meistens laut gedacht, ich wünschte nur, ich könnte so etwas tun), dass ich die Eigenschaftssyntax irgendwie erweitern könnte. Stellen Sie sich so etwas vor:
private string password;
public string Password
{
// Called when being set by a deserializer or a persistence
// framework
deserialize
{
// I could put some backward-compat hacks in here. Like
// weak passwords are grandfathered in without blowing up
this.password = value;
}
get
{
if (Thread.CurrentPrincipal.IsInRole("Administrator"))
{
return this.password;
}
else
{
throw new PermissionException();
}
}
set
{
if (MeetsPasswordRequirements(value))
{
throw new BlahException();
}
this.password = value;
}
serialize
{
return this.password;
}
}
Ich bin mir nicht sicher, ob das nützlich ist oder wie der Zugriff darauf aussehen würde. Aber ich wünschte nur, ich könnte mehr mit Eigenschaften anfangen und sie wirklich wie get- und set-Methoden behandeln.
Erweiterungsmethoden sind nett, aber sie sind eine hässliche Möglichkeit, Probleme zu lösen, die mit echten Mixins sauberer hätten gelöst werden können (siehe Ruby, um zu sehen, wovon ich spreche), zum Thema Mixins. Eine wirklich gute Möglichkeit, sie der Sprache hinzuzufügen, wäre gewesen, Generika für die Vererbung zu verwenden. Auf diese Weise können Sie vorhandene Klassen auf eine schöne objektorientierte Weise erweitern:
public class MyMixin<T> : T
{
// etc...
}
Dies kann folgendermaßen verwendet werden, um eine Zeichenfolge zu erweitern:
var newMixin = new MyMixin<string>();
Es ist weitaus leistungsfähiger als Erweiterungsmethoden, da Sie damit Methoden überschreiben können, z. B. um sie zu verpacken und AOP-ähnliche Funktionen in der Sprache zu ermöglichen.
Entschuldigung für das Geschwätz :-)
Microsoft behebt keine offensichtlichen Fehler im Framework und stellt keine Hooks bereit, damit Endbenutzer diese beheben können.
Es gibt auch keine Möglichkeit, ausführbare .NET-Dateien zur Laufzeit binär zu patchen und keine privaten Versionen von .NET Framework-Bibliotheken anzugeben, ohne die nativen Bibliotheken binär zu patchen (um den Ladeaufruf abzufangen), und ILDASM ist nicht weiterverteilbar, sodass ich nicht automatisieren kann der Patch trotzdem.
Die Möglichkeit, eine Erweiterungsmethode für eine Nullvariable aufzurufen, ist fraglich, z
Objekt a = null; a.MyExtMethod (); // Dies ist aufrufbar. Nehmen wir an, irgendwo wurde MyExtMethod definiert
Es könnte praktisch sein, ist jedoch bei Nullreferenz-Ausnahmethemen nicht eindeutig.
Ein Namensfehler. 'C' von "configuration" in System.configuration.dll sollte groß geschrieben werden.
Ausnahmebehandlung. Ausnahmen sollten wie in Java gewaltsam abgefangen oder ausgelöst werden. Der Compiler sollte sie beim Kompilieren überprüfen. Benutzer sollten sich nicht auf Kommentare für Ausnahmeinformationen innerhalb des Zielaufrufs verlassen.
Die .Parameters.Add () -Methode für den SqlCommand in V1 des Frameworks wurde fürchterlich entworfen - eine der Überladungen würde grundsätzlich nicht funktionieren, wenn Sie einen Parameter mit dem Wert (int) von 0 übergeben würden - dies führte dazu, dass sie erstellt wurden die Methode .Parameters.AddWithValue () für die SqlCommand-Klasse.
ICollection<T>und IList<T>; Zumindest wäre eine kovariante schreibgeschützte Erfassungsschnittstelle IListSource<out T>(mit Enumerator, Indexer und Count) äußerst nützlich gewesen.Transform(Sequence<T>, Func<T,T>)Funktion geschrieben, mit der schnell festgestellt werden konnte, ob die Funktion denselben oder einen anderen Wert zurückgibt. Wenn die Funktion die meisten / alle Argumente nicht ändert, kann die Ausgabesequenz einen Teil / den gesamten Speicher der Eingabesequenz gemeinsam nutzen. Ohne die Möglichkeit, einen Werttyp T bitweise zu vergleichen, muss ein viel langsamerer Vergleich verwendet werden, was die Leistung enorm beeinträchtigt.List<T>, eine Hypothese IListSource<U>(wobei T: U) zu erstellen, obwohl die Klasse diese Schnittstelle nicht explizit implementiert. Es gibt mindestens drei verschiedene Bibliotheken (unabhängig voneinander geschrieben), um diese Funktionalität bereitzustellen (natürlich mit Leistungsnachteilen - wenn eine perfekte Problemumgehung möglich wäre, wäre es nicht fair, sie als Fehler in .NET zu bezeichnen).WeakReference<T>(Sie können leicht Ihre eigenen schreiben, aber es werden Abgüsse intern verwendet.)Predicate<T>vs Func<T,bool>). Ich wünschte oft, wir könnten eine strukturelle Typisierung für Schnittstellen und Delegaten haben, um eine lockerere Kopplung zwischen Komponenten zu erreichen, da es in .NET nicht ausreicht, dass Klassen in unabhängigen DLLs dieselbe Schnittstelle implementieren - sie müssen auch einen gemeinsamen Verweis auf eine dritte haben DLL, die die Schnittstelle definiert.DBNull.Valueexistiert, obwohl nullder gleiche Zweck gleich gut gedient hätte.variable = variable ?? value. In der Tat gibt es einige Stellen in C #, an denen es unnötig an Symmetrie mangelt. Zum Beispiel können Sie schreiben if (x) y(); else z();(ohne geschweifte Klammern), aber Sie können nicht schreiben try y(); finally z();.IList<T>, obwohl ich verwenden würde , IReadableByIndex<out T>und IAppendable<in T>. Viele deiner anderen Dinge sind Quietschgeräusche, denen ich auch zustimmen würde.
IListReader<T>;) - Ich verwende das Wort "Quelle" als Antonyme für "Senke" (eine Nur-Schreib-Schnittstelle).
IListSource<in T>oder IReadableList<out T>. Es kann von Wert sein, wenn Basisschnittstellentypen Methoden enthalten, die nicht in allen Derivaten vorhanden sind, obwohl ich denke, dass es oft gut ist, wenn Schnittstellen etwas spezialisiert sind. Zum Beispiel könnte man eine haben, IList<T>die Größenänderungsmethoden enthält, die möglicherweise funktionieren oder nicht, und eine IResizableList<T>, die dieselben Methoden implementiert, aber garantiert, dass sie funktionieren. Ein solcher Ansatz kann in Fällen nützlich sein, in denen ein Feld entweder den einzigen vorhandenen Verweis auf eine veränderbare Liste oder einen gemeinsamen Verweis auf eine unveränderliche Liste enthält.
if (rl:(list as IResizableList<T>) != null) rl.Add(...);, aber es gibt andere Vorschläge. Als Autor verschiedener Sammlungen und Sammlungsadapter ärgert mich das Schreiben vieler Dummy-Methoden, die Ausnahmen auslösen. Als Sicherheitslüfter möchte ich keine illegalen Methoden aufrufen dürfen. Als IntelliSense-Fan möchte ich nicht, dass sie aufgelistet werden.
Eine Sache , die mich in 1.x abgehakt war , als die Verwendung System.Xml.XmlValidatingReaderder ValidationEventHandler‚s ValidationEventArgsnicht der Basiswert aussetzt XmlSchemaException(markiert intern) , die alle nützlichen Informationen hat wie linenumberund position. Stattdessen wird erwartet, dass Sie dies aus der Message-String-Eigenschaft heraus analysieren oder mithilfe von Reflection ausgraben. Nicht so gut, wenn Sie dem Endbenutzer einen bereinigten Fehler zurückgeben möchten.
Es gefällt mir nicht, dass Sie die Werte einer Aufzählung nicht in einer anderen Aufzählung verwenden können, zum Beispiel:
enum Colors { white, blue, green, red, black, yellow }
enum SpecialColors { Colors.blue, Colors.red, Colors.Yellow }
typeof(Color)! = typeof(SpecialColors).
enum SpecialColors { blue = Colors.blue, red = Colors.red, yellow = Colors.Yellow }
Implizit typisierte Variablen wurden IMO schlecht implementiert. Ich weiß, dass Sie sie wirklich nur verwenden sollten, wenn Sie mit Linq-Ausdrücken arbeiten, aber es ist ärgerlich, dass Sie sie nicht außerhalb des lokalen Bereichs deklarieren können.
Von MSDN:
Der Grund, warum ich denke, dass es eine schlechte Implementierung ist, ist, dass sie es var nennen, aber es ist weit davon entfernt, eine Variante zu sein. Es ist wirklich nur eine Kurzsyntax, wenn Sie nicht den vollständigen Klassennamen eingeben müssen (außer bei Verwendung mit Linq).