C#は読みにくくなっていますか?


15

C#の進歩に伴い、多くの言語機能が追加されました。それは私にとって読めなくなってきています。

例として、Caliburn.Microコードから次のコードスニップを考慮し、ここで

            container = CompositionHost.Initialize(
                   new AggregateCatalog(
                      AssemblySource.Instance.
                             Select(x => new AssemblyCatalog(x))
                               .OfType<ComposablePartCatalog>()
                )
            );

さて、これはほんの小さな例です。

私にはいくつかの質問があります:

  • これは一般的な問題または既知の問題ですか?
  • C#コミュニティは同じことを見つけていますか?
  • これは言語の問題ですか、それとも開発者が使用しているスタイルですか?

他のコードをよりよく理解し、この方法でコードを書くことを避けるための簡単な解決策はありますか?


6
そのラムダ関数は、実際に取得するまで読みにくいです。
リャサル

9
あなたは本当にあなたが思ったほど構文を知らなかったと思います。練習を読むことであなたの例は簡単です。
ChaosPandion

6
@Thomasオーウェンズ:神聖なたわごとの男が、少なくとも私たちに与えるいくつかのオープンそれらを保つために編集の質問に時間を。15分?さあ
スティーブンエバーズ

4
@DannyVarod:1.「いいえ」は受け入れられない答えです2.質問は閉じられています
スティーブンエバーズ

2
@ThorbjørnRavn Andersen-平手打ちから何を学ぶことができますか?これには情報が含まれていません!

回答:


12

言語がどこにあるかについての簡単なメモ:C#は汎用プログラミング言語です。C(C ++など)とは異なり、高度な抽象化を目指しています。Lisp方言とは異なり、実用的な表現力を目指しており、Javaとは異なり、より積極的に駆動されます。Microsoftは需要に迅速に対応しています。

それが、LINQ、ラムダ、奇妙な新しいキーワードの混合物に変わっている理由です-新しい問題のドメインに素早く適応しているので、これは実際には非常に複雑な言語への滑りやすい傾斜です(C ++など)。これはC#自体の問題ではなく、これらの野心的な目標を持つすべての言語の問題です。

コミュニティはこれを認識しており、さらに重要なこととして、C#の背後にいる人々はこれを鋭く知っています(C#5.0の新しい追加の背後にあるものに関するいくつかのブログエントリとポッドキャストは、これらの人々が物事をシンプルに保ちたいと思うことの悪さを示しています)。マイクロソフト、フラッグシップにならないようにいくつかの負荷を軽減しようとしています。つまり、新しい言語(F#)の注目を集めるDLRの導入です。

さらに、C#のコース資料(MS認定を含む)では、問題に応じてC#の異なる(ただし一貫した)使用スタイルを推奨しています-武器を選択してそれに固執します:一部の問題ではFluentスタイルのLINQ、他の問題ではTPLのラムダ、プレーン-ほとんどの古い。


2
「実際の表現力を目指しているLisp方言とは異なり」とはどういう意味ですか?
ジョルジオ

27

いいえ。C#により、コードをより簡潔に記述するためのオプションが増えています。これは使用または悪用される可能性があります。適切に使用すると、コードが読みやすくなります。不適切に使用すると、コードが読みにくくなる可能性があります。しかし、悪いプログラマーは、読みにくいコードを書くスキルを常に持っていました。

同じ問題に関するStackOverflowの例に基づいて、特定の属性を持つ型を見つける2つの例を見てみましょう。

C#2.0:

static IEnumerable<Type> GetTypesWithAttribute<TAttribute>(bool inherit) 
                              where TAttribute: System.Attribute
{
    foreach(Assembly assembly in AppDomain.Current.GetAssemblies())
    {
        foreach(Type type in assembly.GetTypes()) 
        {
            if (type.IsDefined(typeof(TAttribute),inherit))
                yield return type;
        }
    }
}

C#4.0:

IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit) 
                              where TAttribute: System.Attribute
{ 
    return from assembly in AppDomain.CurrentDomain.GetAssemblies()
           from type in assembly.GetTypes()
           where type.IsDefined(typeof(TAttribute),inherit)
           select type;
}

私見、新しい構文は読みやすくします。


新しい構文は実際には読みやすいが、内部で何が起こっているかのように理解しやすいですか?最初の例は理解しやすく、2番目の例は読みやすくなっています。
nawfal

4
@nawfal私の経験では、人々はlinqステートメントよりも「イールドリターン」コンストラクトを理解するのに苦労しています。したがって、2番目の方が読みやすく理解しやすいと主張します。プロセッサの実際の動作とはまったく異なる抽象化にマップされるため、どちらも実際には何が起こっているのかを教えてくれません。
チュウ

正直に言うと、ループを抽象化し、より複雑なコアを持つ1つのループの代わりに(バックグラウンドで個別のループを使用して)個別のLINQクエリでデータを取得するようにコーダーを奨励するため、LINQは嫌いです。
mg30rg

8

LINQが追加されたとき、多くのFluentスタイルのメソッドチェーンと、パラメーターとしてのラムダの受け渡しを含むコーディングスタイルが普及しました。

このスタイルは、慣れると非常に強力です。しかしながら、かなり読みにくいコードを作成すると悪用される可能性があります。インデントは一種のランダムなものですが、あなたの例がそれほど悪いとは思いません(そして、それはこのスタイルのコードの一般的な機能であり、Visual Studioはそれを非常に一貫して自動インデントしません)。

私の職場では、今年初めにコーディング標準をレビューする際にこのコーディングスタイルについて議論し、開発者にそのようなコードを分割することを奨励することにしました。具体的には、関数呼び出し内で匿名オブジェクトを作成および初期化しないことです。したがって、コードは次のようになります。

var assemblyCatalog = AssemblySource.Instance
    .Select(x => new AssemblyCatalog(x))
    .OfType<ComposablePartCatalog>();
var aggregateCatalog = new AggregateCatalog(assemblyCatalog);
container = CompositionHost.Initialize(aggregateCatalog);

1
新しい型を作成し、その後すぐにその型を動的に切り替えるのはちょっと変ではありませんか?
-DeadMG

おそらく、その意図が何であるかを実際に考慮することなく、コードスニペットを切り刻んだだけでしょう。すべてのインスタンス化を独自のコード行に分割して、コードの外観にどのような影響があるかを示したかっただけです。
Carson63000

インデントのせいにします:()。オリジナルは次のとおり

1
私はその答えに完全に同意します。サンプルコードの問題は、新しいC#構文ではなく、ライターが「ワンライナー」コードで賢くしようとしたことです。UNIXからさかのぼるこの古いルールがあります。すべてが1つのことだけを行うべきであり、それをうまくやるべきです。クラスに適用され、メソッドに適用され、そしてもちろん、コード行に適用されます。
ローランブルゴーロイ

4

あなたの例のコードは簡単には読めません

  • 多くの概念(構成、カタログ、集合体、アセンブリ、ComposableParts ...)をいくつかのレベルのネストと混合しますが、呼び出しコードは通常1つのレベルのみを処理する必要があります。サブサブプロパティのチェーンではなく、ネストされたメソッド呼び出しを使用した場合のみ、デメテルの法則に違反しているように見えます。これは、コード行の背後にある意図を多少混乱させます。

  • 奇妙なシングルトンの使用法があります- AssemblySource.Instance.Select()インスタンスがIEnumerableであることを意味しますが、これは少し厄介です。

  • ラムダ式のx変数は見苦しいです。一般的には、ラムダ変数に名前を明らかにする意図を与えようとします-ラムダに精通していない場合でも、読者が関数がどのようなデータであるかを識別するのに役立ちます。

  • OfType<T>()更新したばかりのオブジェクトのコレクションでフィルタリングする必要がある理由は明らかではありません...

ただし、これらのすべての欠陥は、元の開発者がコードを記述した方法と、彼がコードをどのように設計したかに関連しています。これは、C#の最新バージョンおよびラムダ式の外観に固有のものではありません。

より一般的には、コードの読者がラムダの仕組みを知っている場合に役立ちますが、十分に明確な名前を付ければ、ほとんどの場合、.NET 3.5以前のバックグラウンドを持つ人でもコードを読みやすくできます。


2

人気のある言語の新しいバージョンが新しい構造を獲得するたびに、同様の議論が生じます。

私も数年前にこれらの疑問に直面していました(http://gsscoder.blogspot.it/2009/08/use-csharps-features-wisely.html)。

私の意見では、C#はエレガントで一貫した方法で進化しています。

サンプルのコードは複雑ではありません。おそらく、ラムダ式では使用されていません。

問題は、C#がオブジェクト指向言語であるだけでなく、機能的な構成体(http://archive.msdn.microsoft.com/FunctionalCSharp/)もサポートするようになったことです。


1

Lambda構文を理解するのに少し時間がかかりました。私は数学と物理学の経験があります。数式に少し似ていますが、=>ではなく->を使用しています。

数学の例 f(x):= x-> x + 2これは、「xの関数fはxがx + 2にマップされると定義されます」

C#の例 del myDelegate = x => x +2; これは、「myDelegateは、myDelegate(x)がxをx + 2にマップする関数です

数学とプログラミングの不一致は本当に助けにはなりませんが、C ++では「property of」(urrgghh!)としてすでに取り上げられていたと思いますが

http://en.wikipedia.org/wiki/List_of_mathematical_symbols


「私は->がすでに「property of」(urrgghh!)としてC ++で取り上げられていたと思いますが)あたかも!C ++では、「動的に割り当てられたプロパティ...」という意味です。何かが動的でない場合は、他のすべての言語と同様にピリオドを使用します。
mg30rg
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.