17


5

このことを考慮:

var me = new {FirstName = "John"、LastName = "Smith"};

これが可能になるので、これで問題ありません。

Console.WriteLine( "{0} {1}"、me.FirstName、me.LastName);

しかし、これはできません。

public T GetMe(){return new {FirstName = "John"、LastName = "Smith"};} }

Tの種類がわからないから

私たちはこれを行うことができます:

パブリックオブジェクトGetMe(){return new {FirstName = "John"、LastName = "Smith"}; }

しかし、それらにアクセスするには、リフレクションを使用してオブジェクトのプロパティを検査する必要があります。

var p = new Prog();オブジェクトo = p.GetMe(); t = o.GetType();と入力します。 foreach(t.GetProperties()のvar prop){Console.WriteLine(prop.Name ":" prop.GetValue(o、null)); }

しかし、定義時に匿名型に名前を付けることができたらどうでしょうか。 もちろん、もはや匿名ではなくなりますが、通常のクラス定義よりも簡潔で保守性に優れています。

このことを考慮:

public Person GetMe(){新しいパブリッククラスを返すPerson {FirstName = "John"、LastName = "Smith"}; }

そのため、クラスを明示的に定義しなくても、メソッドから複雑なLinqクエリの結果を返すことができます。

この比較的複雑なLinqクエリを考えます。

リストリスト= new List(); var query =リスト内の番号から新規選択{数値=数値、平方=数値*数値、絶対= Math.Abs​​(数値)、範囲= Enumerable.Range(0、number)};

次のようにクラスを定義する代わりに、

パブリッククラスMyNumbers {public int Number {get;}セット; public int Square {get;}セット; public int Absolute {get;}セット; }パブリックIEnumerable範囲{get;}セット; }}

メソッドからクエリ変数を返すために、代わりにこれを実行することができます。

リストリスト= new List();リスト内の数値から戻る新しいパブリッククラスMyNumbersを選択します{数値=数値、平方=数値*数値、絶対= Math.Abs​​(数値)、範囲= Enumerable.Range(0、number)}。

7 Answer


13


実際には、メソッドから無名型を取り戻すためにできる「ハック」があります。 このことを考慮:

パブリックオブジェクトMyMethod(){var myNewObject = new {stringProperty = "こんにちは、World!"、intProperty = 1337、boolProperty = false}。

myNewObjectを返します。 }

public T Cast(オブジェクトobj、T型){return(T)obj; }

これができます。

var obj = MyMethod(); var myNewObj = Cast(obj、new {stringProperty = ""、intProperty = 0、boolProperty = false});

myNewObjは、匿名型と同じTypeのオブジェクトになります。


9


必要な言語機能は次のとおりです。

public var GetMe()
{
    return new { FirstName = "John", LastName = "Smith" };
}

つまり、 `var`はメソッドの戻り値の型として有効であり、コンパイラは返されるものから実際の型を推測します。 あなたはそれからコールサイトでこれをしなければならないでしょう:

var me = GetMe();

同じ型のメンバーを持つ2つの無名型は同じ型になります。したがって、同じパターンを返す他の関数を書いた場合、それらは同じ型になります。 BがAのメンバーのサブセットを持つ任意の型AおよびBの場合、AはBと代入互換です(BはAの基本クラスに似ています)。 あなたが書いた場合:

public var GetMeFrom(var names)
{
    return new { FirstName = names["First"], LastName = names["Last"] };
}

コンパイラは、これを2つの型パラメータを持つ一般的なメソッドとして効果的に定義します。「T1」は名前の型、「T2」はインデクサによって文字列を受け入れる型として返されます。 T1`は、文字列を受け付けるインデクサーを持たなければならないように制約されます。 そしてコールサイトでは、文字列を受け入れて好きな型を返すインデクサを持つものなら何でも渡して、それが `GetMeFrom`によって返される型の FirstName`と `LastName`の型を決定します。

そのため、型推論はあなたに代わってこれらすべてを理解し、自動的にコードから発見可能な型制約を捕らえます。


5


私見根本的な問題は匿名型とは関係ありませんが、クラスを宣言するのはあまりにも冗長です。

オプション1:

あなたがこのようなクラスを宣言することができれば:

public class MyClass
{ properties={ int Number, int Square, int Absolute, IEnumerable Range } }

あるいは(タプルの例のような)他の似たような素早い方法では、コードを保存するためだけに匿名型を使ってハックなことをする必要性を感じないでしょう。

「サービスとしてのコンパイラ」がC#5に入ったら、うまく統合できればいいでしょう。メタプログラミングを使ってこの種の問題をきれいに解決できるようになるでしょう。 1958年のようなパーティー!

オプション2:

あるいは、C#4では、匿名型を `dynamic`として渡すだけで、すべてのキャストを回避できます。 もちろん、変数の名前を変更すると、ランタイムエラーが発生します。

オプション3:

C#がCと同じ方法で総称を実装するのであれば、無名型をメソッドに渡すことができ、それに適切なメンバーがある限り、それはコンパイルされるだけです。 あなたは静的型の安全性のすべての利点を手に入れるでしょう、そして欠点のどれもありません。 私がC#で `where T:ISomething`とタイプしなければならない度に、私は彼らがこれをしなかったことに悩まされます!


4


あなたが説明しているもの(名前付き匿名型)は基本的に「タプル型」です。

私はそれらがC#への素晴らしい追加になると思います。

私がC#のためにそのような機能を設計していたならば、私はこのような構文を使ってそれを公開するでしょう:

tuple

あなたができるように:

public tuple GetStuff()
{
}

それから、匿名型の定義を変更します。

new { x = 2, y = 2}

匿名型ではなく、型として `tuple`を持っていました。

これを現在のCLRで機能させるには、やや注意が必要です。パブリック署名で匿名型を指定すると、別々にコンパイルされたアセンブリ間でそれらを統合できるようにする必要があるためです。 これは、タプル型を使用する任意のアセンブリ内に「モジュールコンストラクター」を埋め込むことによって実現できます。 例はhttps://stackoverflow.com/questions/185836/equivalent-of-class-loaders-in-net [この投稿]を参照してください。

そのアプローチの唯一のマイナス面は、それが型生成のためのCLRの "lazy"モデルを尊重しないということです。 つまり、多くの異なるタプル型を使用するアセンブリでは、やや遅いロード型が発生する可能性があります。 より良い方法は、タプル型のサポートを直接CLRに追加することです。

しかし、CLRを変更することとは別に、私はモジュールコンストラクタのアプローチがこのようなことをする最善の方法だと思います。


1


私はこの機能が大好きだ、私はこれを望んでいたことが何度もありました。

良い例はXMLの処理です。 あなたはそれらを解析してオブジェクトを取り戻します、しかしそれからあなたは呼び出し側に送り返すためにオブジェクトの具体的なバージョンを作る必要があります。 XMLはかなり変更されることが多く、それを処理するために多くのクラスを作成する必要があります。 あなたがvarとしてLinqToXmlを使用してオブジェクトを構築することができたら、それを単に返すことができたらそれは素晴らしいことではないですか?


0


私はこれがタプルにとって素晴らしいコンパイラマジックになると思います。

タプルを作成する:

(int、string、Person)tuple =(8、 "hello"、new Person());

に相当:

タプルタプル= new Tuple(8、 "hello"、new Person());

関数内では:

public(int、string、Person)GetTuple(){return ... }

値を取得する:

int number = tuple [1];文字列text = tuple [2];人person =タプル[3];


-1


FirstNameプロパティとLastNameプロパティを持つインタフェースを作成してそれを使用できますか。