C#の進歩に伴い、多くの言語機能が追加されました。それは私には読めなくなってきたところまで来ています。
例として、Caliburn.Microのコード here から次のコードを切り取ります。
container = CompositionHost.Initialize(
new AggregateCatalog(
AssemblySource.Instance.
Select(x => new AssemblyCatalog(x))
.OfType<ComposablePartCatalog>()
)
);
さて、これはほんの小さな例です。
いくつか質問があります。
他のコードをよりよく理解し、このようにコードを記述しないようにする簡単な解決策はありますか?
言語がどこにあるかについての簡単なメモは、それを明確にする必要があります:C#は 汎用プログラミング言語 ;です。 Cとは異なり(C++のように)、高度な抽象化を目指しています。 LISPの方言とは異なり、実用的な表現力を目指しており、Javaとは異なり、より積極的に推進されています-マイクロソフトは需要に迅速に対応しています。
これが、LINQ、ラムダ、および奇妙な新しいキーワードの混合に変化している理由です-新しい問題の領域にすばやく適応しており、これは確かに滑りやすい勾配です非常に複雑なため、C++のように正しく使用できる言語はほとんどありません。これはC#自体の問題ではなく、これらの野心的な目標を持つすべての言語の問題です。
コミュニティはこれを認識しており、さらに重要なことに、C#の背後にいる人たちはこれを鋭く認識しています(C#5.0の新しい追加の背後にあるものに関するいくつかのブログエントリとポッドキャストは、これらの人が物事をシンプルに保つことの悪さを示しています)。 Microsoftis旗艦の負荷の一部を取り除き、それがターピットにならないようにします:DLRの導入、明るいスポットライト新しい言語(F#)。
さらに、C#のコース資料(MS認定を含む)は、問題に応じてC#の異なる(ただし一貫した)スタイルの使用を推奨しています-武器を選択してそれに固執します。 -ほとんどの人にとって古い。
いいえ。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;
}
私見、新しい構文により読みやすくなりました。
LINQが追加されたとき、それは多くのFluentスタイルのメソッドチェーンを含むコーディングスタイルと、ラムダをパラメーターとして渡すことを普及させました。
このスタイルは、慣れれば非常に強力です。 ただしかなり読みにくいコードを作成するために悪用される可能性があります。インデントはランダムなものですが(これはこのスタイルのコードの一般的な機能ですが、Visual Studioは非常に一貫して自動インデントを行いません)、あなたの例は悪くないと思います。
私の職場では、今年の初めにコーディング標準をレビューするときにこのコーディングスタイルについて話し合い、開発者にそのようなコードを分割するように勧めることにしました。具体的には、関数呼び出し内で匿名オブジェクトを作成および初期化しないことです。したがって、コードは次のようになります。
var assemblyCatalog = AssemblySource.Instance
.Select(x => new AssemblyCatalog(x))
.OfType<ComposablePartCatalog>();
var aggregateCatalog = new AggregateCatalog(assemblyCatalog);
container = CompositionHost.Initialize(aggregateCatalog);
あなたの例のコードは簡単に読めません
多くの概念(構成、カタログ、集合体、アセンブリ、ComposableParts ...)をいくつかのレベルのネストと混合しますが、呼び出し側のコードは通常、1つのレベルのみを処理する必要があります。サブサブプロパティのチェーンではなく、ネストされたメソッド呼び出しでのみ、デメテルの法則の違反のように見えます。これにより、コード行の背後にある意図が多少混乱します。
奇妙なシングルトンの使い方があります-AssemblySource.Instance.Select()
は、インスタンスがIEnumerableであることを意味しますが、これは少し厄介です。
ラムダ式のx変数は醜いです。一般的には、ラムダ変数に意図を明らかにする名前を付けようとします。ラムダに慣れていない場合でも、関数がどのような種類のデータであるかを読者が識別できるようにします。
更新したばかりのオブジェクトのコレクションをOfType<T>()
でフィルタリングする必要がある理由は明らかではありません...
ただし、これらの欠陥はすべて、元の開発者がコードを書いた方法と、コードをどのように表現力豊かに設計したかに関係しています。これは、C#の最新バージョンやラムダ式の外観に固有のものではありません。
より一般的には、コードの読者がラムダの動作を知っていると役立ちますが、十分に明確な名前を付けることで、ほとんどの場合、.NET 3.5より前のバックグラウンドを持つ人でもコードを読みやすくすることができます。
人気のある言語の新しいバージョンが新しい構成要素を獲得するときはいつでも、同様の議論が起こります。
私も数年前にこれらの疑いを持っていました(http://gsscoder.blogspot.it/2009/08/use-csharps-features-wisely.html)。
私の意見では、C#はエレガントで一貫した方法で進化しています。
サンプルのコードは複雑ではありません。ラムダ式を使用していない可能性があります。
問題は、C#がオブジェクト指向言語であるだけでなく、関数構成体(http://archive.msdn.Microsoft.com/FunctionalCSharp/)もサポートするようになったことです。
Lambda構文を理解するのに少し時間がかかりました。私は数学と物理学の出身です。数式と少し似ていますが、=>の代わりに->を使用します。
数学の例f(x):= x-> x + 2これは、「xの関数fはxとして定義され、x + 2にマップされます
c#の例del myDelegate = x => x +2;これは、「myDelegateは、myDelegate(x)がxをx + 2にマップするような関数です。
数学とプログラミングの間の不一致は本当に役に立たないが、私はおそらく->はすでにC++で「のプロパティ」(urrgghh!)