C#または.NET Framework全般の最大の設計上の欠陥は何ですか?
例:NULL不可の文字列型はなく、IDataReaderから値をフェッチするときにDBNullをチェックする必要があります。
C#または.NET Framework全般の最大の設計上の欠陥は何ですか?
例:NULL不可の文字列型はなく、IDataReaderから値をフェッチするときにDBNullをチェックする必要があります。
回答:
私はこの投稿に強く同意します(ToStringがないことをうんちする人のために、クラスにカスタム形式を提供するデバッガー属性があります)。
上記のリストに加えて、次の合理的なリクエストも追加します。
T : new(string)、またはどこT : new(string, int)var e = new Foo(); e { Bar = baz };Either<T>」のような効率的な閉じた代数型はそうではないので、閉じた代数型を宣言し、それに徹底的なパターンマッチングを適用する方法が欲しいです(基本的にはビジターパターンのファーストクラスのサポートですが、はるかに効率的); したがって、列挙型を取得し、徹底的なパターンマッチングのサポートでそれらを拡張し、無効なケースを許可しないでください。System.IOようなクラスのStream設計がやや不十分であるという別の投稿に同意します。スローするためにいくつかの実装を必要とするインターフェイスNotSupportedExceptionは、悪い設計です。IListそれよりもはるかに単純なはずです。実際、これは、などの具体的なコレクションインターフェイスの多くに当てはまる可能性がありますICollection。INotifyPropertyChangedフィールド名を文字列として受け取る、のようなインターフェイスのフィールド名とメンバー名を安全に反映する方法を提供します。これを行うには、ラムダをaMemberExpressionで取る拡張メソッドを使用します。() => Foo、しかしそれはあまり効率的ではありません、
nameof()は単一メンバー名の演算子を追加しましたが、ジェネリックでは機能しません(nameof(T) == "T"実際の型引数の名前の代わりに:実行する必要がありますtypeof(T).Name))-また、「パス」文字列を取得することもできませんたとえばnameof(this.ComplexProperty.Value) == "Value"、可能なアプリケーションを制限します。IArithmeticます。他の便利な共有オペレータインターフェイスも可能ですが、readonlyキーワードがあり、C#6.0では読み取り専用の自動プロパティが追加されましたが、不変の型と値に対する真の言語サポートほど厳格ではありません。今のところそれで十分だと思います。これらはすべて、私が先週遭遇した苛立ちです。本当に気をつければ、おそらく何時間も続けることができるでしょう。C#4.0はすでに名前付き、オプション、デフォルトの引数を追加していますが、これは私が強く承認します。
今、1つの不合理な要求のために:
かなりお願いしますか?:-)
List<T>百万のTを持っています。スナップショットを効率的に作成することをどのように提案しますか?#21:使用するreadonlyキーワードを....ここにいくつかの良い提案がありますが、それらはほとんどそれだけです-提案であり、設計上の欠陥ではありません。
Reset()方法IEnumerator<T>は間違いでした(イテレータブロックの場合、言語仕様はこれが例外をスローすることさえ要求します)IEnumerable<out T>およびFunc<in T, out TResult>などList<T>)に共変/反変性のサポートが追加されましたが、具体的な型(など)は追加されていません。ApplicationException むしろ不利になりました-それは間違いでしたか?Contains、複数の操作する(、then Add)、個別の操作を同期するコレクションはそれほど有用ではありません。
System.Collections.Concurrent、とはTryAdd、GetOrAdd、TryRemove、などは、.NET Framework 4.0で追加されました-工場出荷時のデリゲートを受け入れる方法は、工場でのみ、キーごとに一度呼び出されます保証するものではありませんが。using/lockパターンをかもしれません-おそらく、再利用可能な(拡張可能な?)構文を共有できるようになります。を返しIDisposable、使用することでこれをシミュレートusingできますが、より明確であった可能性がありますFoo(SqlConnection! connection)(nullチェック/を挿入する)のthrowは良いでしょう(int?などとは対照的です)
dynamicます。または、次のように有効にすることもできますforeach展開中にwhileの外。つまり、anon-methods / lambdasは、反復ごとに1つではなく、単一の変数をキャプチャします(スレッド化/非同期などで苦痛)
ApplicationExceptionは間違いだと言いました-彼らが望んでいたほど役に立たなかったのです。彼らはまたそれがあったSystem.Exceptionはずだと言ったabstract。
TextWriterはベースです StreamWriterのクラスです。wtf?
それはいつも私を極端に混乱させます。
小さなC#petpeev-コンストラクターはC ++ / Java構文を使用して、コンストラクターをクラスと同じ名前にします。
New()またはctor()はるかに良かったでしょう。
そして確かに、coderushなどのツールを使用すると、クラスの名前を変更する際の問題は少なくなりますが、読みやすさのPOVから、New()は非常に明確になります。
class Foo { new(int j) {i = j} int i; }
New --uppercaseキーワードは慣例に反し)、設計上の欠陥と呼ぶことを躊躇します。彼らは既存のC ++ / Java開発者を引き付けたいと考えていました。そして、多くの愚かな古い構文規則を借りることで、間違いなく彼らの目標を達成することができました。
私はあなたができないことを理解していません
ここで、T:new(U)
したがって、ジェネリック型Tにはデフォルト以外のコンストラクターがあることを宣言します。
編集:
私はこれをしたい:
public class A
{
public A(string text)
{
}
}
public class Gen<T> where T : new(string text)
{
}
私がこれに最初に言及したことに本当に驚いています:
ADO.NET型付きデータセットは、null許容型のプロパティとしてnull許容列を公開しません。あなたはこれを書くことができるはずです:
int? i = myRec.Field;
myRec.Field = null;
代わりに、これを書く必要がありますが、これはばかげています。
int? i = (int?)myRec.IsFieldNull() ? (int?)null : myRec.Field;
myRec.SetFieldNull();
これは.NET2.0では厄介でしたが、きちんとしたLINQクエリで上記のようなジゲリーポケリーを使用する必要があるため、さらに厄介です。
生成されたAdd<TableName>Rowメソッドがnull許容型の概念に同様に無意味であることも厄介です。生成されたTableAdapterメソッドはそうではないので、なおさらです。
.NETには、開発チームが「わかりました。もうすぐです。出荷してください」と言ったような気がするものはあまりありません。しかし、これは確かにそうです。
DBNull.Valueであった場合に、特別な値を要求するという不条理を忘れないでくださいnull。幸い、LINQ-to-SQLはNULLにnullを使用します。
編集
5.私のもう1つの厄介な点は、System.Reflection.BindingFlagsが、使用するメソッドに応じてどのように異なる用途を持っているかです。たとえばFindFieldsでは、CreateInstanceまたはSetFieldはどういう意味ですか?これは、混乱を招くこの列挙の背後にある意味を過負荷にした場合です。
設計上の欠陥だと言っても過言ではありませんが、VBと同じ方法でラムダ式を推測できれば本当に素晴らしいと思います。
VB:
Dim a = Function(x) x * (x - 1)
C#
これができればいいのですが:
var a = x => x * (x - 1);
これを行う代わりに:
Func<int, int> a = x => x * (x - 1);
それほど長くはないことはわかっていますが、コードゴルフではすべてのキャラクターが気の毒です!彼らはこれらのプログラミング言語を設計するときにそれを考慮に入れていませんか?:)
(int x) => x * (x -1);は意味するFunc<int, int>ことも、意味することもありますExpression<Func<int, int>>
+定義されていないため、C#はできませんobject。
System.Objectのクラス:
EqualsとGetHashCode-すべてのクラスが比較可能またはハッシュ可能であるとは限らないため、インターフェイスに移動する必要があります。IEquatableまたはIComparable(または同様のもの)が思い浮かびます。
ToString-すべてのクラスを文字列に変換できるわけではないため、インターフェイスに移動する必要があります。IFormattable(または同様のもの)が思い浮かびます。
ICollection.SyncRootのプロパティ:
ジェネリックは最初からそこにあるべきでした:
EqualityComparer<T>.Default正しく更新することだけです。次に、var dict = new Dictionary<object, string>(EqualityComparer<object>.Default)との両方var dict = new Dictionary<object, string>()が参照比較/同等性を使用します。
EqualityComparer<T>.Defaultです。ルックアップのたびにチェックする必要はありません。比較子はDictionaryインスタンスのプロパティであり、それぞれDictionaryが使用しているものを認識しています。
私を苛立たせるものの1つはPredicate<T> != Func<T, bool>パラドックスです。これらは両方ともタイプのデリゲートT -> boolですが、割り当てとの互換性はありません。
一部の人々(ISV)は、dotNetランタイムを必要としないネイティブ実行可能ファイルを作成するために、ビルド時にマシンコードにコンパイルしてリンクできることを望んでいます。
私たちは権利について多くを知っていますOOテクニックます。デカップリング、コントラクトによるプログラミング、不適切な継承の回避、例外の適切な使用、オープン/クローズドプリンシパル、リスコフの置換可能性など。まだ、.Netフレームワークはベストプラクティスを採用していません。
私にとって、.Netの設計における最大の欠陥は、巨人の肩の上に立っているわけではありません。フレームワークを使用するプログラマーの大衆に、理想的とは言えないプログラミングパラダイムを宣伝する。
MSがこれに注意を払っていれば、ソフトウェアエンジニアリングの世界は、この10年間で品質、安定性、スケーラビリティの面で大きな飛躍を遂げた可能性がありますが、残念ながら、後退しているようです。
C#のswitchステートメントが好きではありません。
こんなもの欲しい
switch (a) {
1 : do_something;
2 : do_something_else;
3,4 : do_something_different;
else : do_something_weird;
}
したがって、これ以上の中断(忘れやすい)や、異なる値をコンマで区切る可能性はありません。
switchCの意図的に不自由なバージョンをエミュレートするすべての言語で根本的に壊れています(速度が最適化されています!)。VBの方がはるかに優れていますが、パターンマッチングを使用する言語(Haskell、F#…)よりもまだ光年遅れています。
リスナーを明示的にチェックする必要があるC#のイベント。たまたまそこにいた人に放送するというのがイベントのポイントではなかったのでしょうか。ないのに?
ネストされた/再帰的なイテレータのひどい(そしてほとんどの人にはまったく見えない)O(N ^ 2)の振る舞い。
私は彼らがそれについて知っていることを非常にうんざりしています それを修正する方法をますが、それは包含に値する十分な優先順位を持っているとは見なされていません。
私は常にツリーのような構造で作業しており、このように非常に高価な操作を誤って導入した場合は、そうでなければ賢い人々のコードを修正する必要があります。
「yieldforeach」の利点は、構文が単純で簡単なため、正確でパフォーマンスの高いコードが促進されることです。これは、プラットフォームの長期的な成功のために新しい機能を追加する前に、彼らが目指すべき「成功の落とし穴」です。
インターフェイスの静的メンバーとネストされたタイプ。
インターフェース部材は、インタフェースに固有のタイプのパラメータ(ある場合に特に有用であるなどenum)。列挙型をインターフェイス型にネストすると便利です。
null どこにでも。
const どこにも。
APIに一貫性がありません。たとえば、配列を変更voidするとリターンが返されますが、に追加するStringBufferと同じミュータブルが返されますStringBuffer。
コレクションインターフェイスは、不変のデータ構造と互換性がありません。たとえばAdd、inSystem.Collections.Generic.IList<_>は結果を返すことができません。
構造型はないのでSystem.Windows.Media.Effects.SamplingMode.Bilinear、単にBilinear。
IEnumerator不変である必要があるときにクラスによって実装される可変インターフェースstruct。
平等との比較が混乱している:あなたは持っているSystem.IComparableし、Equalsしかし、あなたはまた、持っているSystem.IComparable<_>、System.IEquatable、System.Collections.IComparer、System.Collections.IStructuralComparable、System.Collections.IStructuralEquatable、System.Collections.Generic.IComparerとSystem.Collections.Generic.IEqualityComparer。
タプルは構造体である必要がありますが、構造体は末尾呼び出しの除去を不必要に禁止するため、最も一般的で基本的なデータ型の1つが不必要に割り当てられ、スケーラブルな並列処理が破壊されます。
IEnumeratorますか?
列挙型として0月明かり
列挙型の特性: http //blogs.msdn.com/abhinaba/archive/2007/01/09/more-peculiarites-of-enum.aspx
この良い例で示されているように: http //plus.kaist.ac.kr/~shoh/postgresql/Npgsql/apidocs/Npgsql.NpgsqlParameterCollection.Add_overload_3.html
私の提案では、「@」記号を有効に活用してください。
の代わりに:
if((myVar&MyEnumName.ColorRed)!= 0)
これを使って:
if((myVar&MyEnumName.ColorRed)!= @ 0)
すでに他の人が作った良い点の長いリストに追加するには:
DateTime.Now == DateTime.Now すべてではありませんが、ほとんどの場合。
String不変であるものには、構築と操作のための多くのオプションがありますが、StringBuilder(可変である)にはありません。
Monitor.Enterそして、Monitor.Exitインスタンスメソッドである必要があったので、ロックするために特定のオブジェクトを新しくする代わりに、を新しくしMonitorてロックすることができます。
デストラクタは、デストラクタと呼ばれるべきではありませんでした。ECMA仕様では、それらをファイナライザーと呼んでいます。これは、C ++の群集にとってはそれほど混乱しませんが、言語仕様では、それらをデストラクタと呼んでいます。
DateTime.Now一つは、世界で最も明白な競合状態ですが、残りの1
プロパティの使い方がイライラすることがあります。私はそれらをJavaのgetFoo()およびsetFoo()メソッドと同等のものと考えるのが好きです。しかし、そうではありません。
場合プロパティ使用上のガイドラインのプロパティは直列化ので、任意の順序で設定することができるはずという状態は、セッター時の検証のため、彼らがしている役に立たない、働くことができます。オブジェクトが無効な状態になるのを防ぎたい背景から来た場合、プロパティは解決策ではありません。時々私は私たちが物事の種類は、私たちがしているものに限られているので、彼らは、公共のメンバーよりも優れているだけでどのように見ることができないはずのプロパティで行うこと。
そのために、私は常に、プロパティ構文を何らかの方法で拡張できることを望んでいました(これは、ここではほとんど大声で考えています。このようなことができればと思います)。次のようなものを想像してみてください。
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;
}
}
それが役立つかどうか、またはそれらにアクセスすることがどのように見えるかはわかりません。しかし、プロパティをさらに活用して、getメソッドやsetメソッドのように扱うことができればと思います。
拡張メソッドは素晴らしいですが、ミックスインに関しては、実際のミックスインでよりクリーンに解決できた可能性のある問題を解決するための醜い方法です(ルビーを見て、私が話していることを確認してください)。それらを言語に追加するための本当に良い方法は、ジェネリックを継承に使用できるようにすることでした。これにより、既存のクラスをオブジェクト指向の優れた方法で拡張できます。
public class MyMixin<T> : T
{
// etc...
}
これは、次のように使用して文字列を拡張できます。
var newMixin = new MyMixin<string>();
メソッドをオーバーライドできるため、拡張メソッドよりもはるかに強力です。たとえば、メソッドをラップして、言語内でAOPのような機能を使用できます。
暴言でごめんなさい:-)
Microsoftはフレームワークの明らかなバグを修正せず、エンドユーザーが修正できるようにフックを提供しません。
また、実行時に.NET実行可能ファイルにバイナリパッチを適用する方法も、ネイティブライブラリにバイナリパッチを適用せずに.NET Frameworkライブラリのプライベートバージョンを指定する方法もありません(ロード呼び出しをインターセプトするため)。ILDASMは再配布できないため、自動化できません。とにかくパッチ。
null変数で拡張メソッドを呼び出すことができるかどうかは議論の余地があります。
オブジェクトa = null; a.MyExtMethod(); //これは呼び出し可能であり、どこかでMyExtMethodが定義されていると想定します
便利かもしれませんが、null参照の例外トピックについてはあいまいです。
1つの命名「欠陥」。System.configuration.dllの「configuration」の「C」は大文字にする必要があります。
例外処理。Javaのように例外を強制的にキャッチまたはスローする必要があり、コンパイラはコンパイル時に例外をチェックする必要があります。ユーザーは、ターゲット呼び出し内の例外情報のコメントに依存しないでください。
ICollection<T>ありませんIList<T>。少なくとも、共分散の読み取り専用コレクションインターフェイスIListSource<out T>(列挙子、インデクサー、およびカウントを使用)は非常に便利でした。Transform(Sequence<T>, Func<T,T>)、関数が同じ値を返すか異なる値を返すかをすばやく判断する必要がある関数を作成していました。関数が引数のほとんど/すべてを変更しない場合、出力シーケンスは入力シーケンスからの一部/すべてのメモリを共有できます。値型Tをビット単位で比較する機能がないと、はるかに遅い比較を使用する必要があり、パフォーマンスが大幅に低下します。List<T>、仮想IListSource<U>(T:Uの場合)にキャストできます。この機能を提供するために、少なくとも3つの 異なる ライブラリ(独立して記述)があります(もちろん、パフォーマンスの欠点があります。完全な回避策が可能である場合、それを.NETの欠陥と呼ぶのは公平ではありません)。WeakReference<T>(自分で簡単に書くことができますが、内部でキャストを使用します)。Predicate<T>vsなどFunc<T,bool>)私にとって厄介なものでした。.NETでは、独立したDLLのクラスが同じインターフェイスを実装するだけでは不十分であるため、コンポーネント間の疎結合を実現するために、インターフェイスとデリゲートの構造型を設定できればと思うことがよくあります。インターフェイスを定義するDLL。DBNull.Valuenull同じ目的を同じようにうまく果たしたとしても存在します。variable = variable ?? value。実際、C#には、不必要に対称性に欠ける場所がいくつかあります。たとえば、if (x) y(); else z();(中括弧なしで)書くことはできますが、書くことはできませんtry y(); finally z();。IList<T>、私が使用したいのに、IReadableByIndex<out T>とIAppendable<in T>。あなたの他のものの多くは私も同意するスコークです。
IListReader<T>ます;)-私は「シンク」(書き込み専用インターフェース)の反意語として「ソース」という言葉を使用します。
IListSource<in T>またはIReadableList<out T>。基本インターフェイスタイプに、すべての派生物に存在しないメソッドを含めることには価値がありますが、インターフェイスをある程度特殊化することはしばしば良いことだと思います。たとえば、機能IList<T>する場合と機能しない場合があるサイズ変更メソッドを含む、およびIResizableList<T>同じメソッドを実装するが、機能することを保証するを使用できます。このようなアプローチは、フィールドが可変リストへの唯一の現存する参照、または不変リストへの共有参照のいずれかを保持する可能性がある場合に役立つ可能性があります。
if (rl:(list as IResizableList<T>) != null) rl.Add(...);他の提案もあります。さまざまなコレクションとコレクションアダプターの作成者として、私を苛立たせているのは、例外をスローするダミーメソッドをたくさん書いていることです。型安全ファンとして、私は違法なメソッドを呼び出させたくありません。IntelliSenseファン、リストに表示されたくありません。
たとえば、ある列挙型の値を別の列挙型で使用できないのは気に入らないでしょう。
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 }
暗黙的に型指定された変数は、IMOの実装が不十分でした。実際にはLinq式を操作する場合にのみ使用する必要があることはわかっていますが、ローカルスコープ外で宣言できないのは面倒です。
MSDNから:
実装が不十分だと思う理由は、彼らがそれをvarと呼んでいるからですが、それはバリアントになるにはほど遠いです。これは、完全なクラス名を入力する必要がないための単なる省略構文です(Linqで使用する場合を除く)