Linqクエリによって入力されたデータグリッドがあります。データグリッドのフォーカスされた行が変更されたら、そのオブジェクトのプロパティの1つに等しい変数を設定する必要があります。
私は試した...
var selectedObject = view.GetRow(rowHandle);
_selectedId = selectedObject.Id;
...しかし、コンパイラはこれをまったく気にしません(「埋め込みステートメントを宣言またはラベル付きステートメントにすることはできません」)。
宿泊施設へのアクセスは簡単なようです。実行時にオブジェクトを検査すると、期待するすべてのプロパティが表示されますが、それらにアクセスする方法がわかりません。
匿名オブジェクトのプロパティにアクセスするにはどうすればよいですか?
説明のために編集:
私はたまたまDevExpressXtraGridコントロールを使用しています。このコントロールに、いくつかの異なるオブジェクトで構成されたLinqクエリをロードしたため、データが既に持っている1つのクラスに実際に準拠していません(つまり、これを何にもキャストできません)。
.NET3.5を使用しています。
View.GetRow(rowHandle)メソッドの結果を表示すると、次のような匿名型が取得されます。
{ ClientId = 7, ClientName = "ACME Inc.", Jobs = 5 }
私の目的は、この匿名型からClientIdを取得して、他のこと(そのクライアントレコードを含むフォームをロードするなど)を実行できるようにすることです。
私は初期の回答でいくつかの提案を試しましたが、このClientIdを取得できるポイントに到達できませんでした。
リフレクションを使おうとしたことがありますか?サンプルコードスニペットは次のとおりです。
// use reflection to retrieve the values of the following anonymous type
var obj = new { ClientId = 7, ClientName = "ACME Inc.", Jobs = 5 };
System.Type type = obj.GetType();
int clientid = (int)type.GetProperty("ClientId").GetValue(obj, null);
string clientname = (string)type.GetProperty("ClientName").GetValue(obj, null);
// use the retrieved values for whatever you want...
特定のキーのデータ項目の値を取得するための一般的なソリューション
public static T GetValueFromAnonymousType<T>( object dataitem, string itemkey ) {
System.Type type = dataitem.GetType();
T itemvalue = (T)type.GetProperty(itemkey).GetValue(dataitem, null);
return itemvalue;
}
例:
var dataitem = /* Some value here */;
bool ismember = TypeUtils.GetValueFromAnonymousType<bool>(dataitem, "IsMember");
匿名型の問題の1つは、関数間で匿名型を使用することが難しいことです。匿名型に「名前を付ける」方法はないため、それらの間でキャストすることは非常に困難です。これにより、メタデータに表示され、ユーザー定義のすべての型式として使用されなくなります。
上記で使用しているAPIを正確に知ることはできません。ただし、APIが強く型付けされた匿名型を返すことはできないため、selectedObjectはオブジェクトに型付けされていると思います。 C#3.0以下は動的アクセスをサポートしていないため、実行時に使用可能であってもプロパティIDにアクセスできません。
これを回避するには、次のいずれかを行う必要があります
[〜#〜]編集[〜#〜]
匿名型キャストをハックする方法のサンプルを次に示します
public T AnonymousTypeCast<T>(object anonymous, T typeExpression) {
return (T)anonymous;
}
...
object obj = GetSomeAnonymousType();
var at = AnonymousTypeCast(obj, new { Name = String.Empty, Id = 0 });
それがハッキーである理由は、これを破るのが非常に簡単だからです。たとえば、匿名型が最初に作成されたメソッドで。そこに別のプロパティを追加すると、上記のコードはコンパイルされますが、実行時に失敗します。
動的型を使用すると、リフレクションを使用せずに実行時に匿名型のプロパティにアクセスできます。
var aType = new { id = 1, name = "Hello World!" };
//...
//...
dynamic x = aType;
Console.WriteLine(x.name); // Produces: Hello World!
動的型の詳細については、こちらをご覧ください: http://msdn.Microsoft.com/en-us/library/dd264736.aspx
匿名型を渡し、それらを再キャストしようとしていたとき、最終的には、オブジェクトの操作を処理するラッパーを作成する方が簡単であることがわかりました。これはそれについてのブログ投稿へのリンクです。
http://somewebguy.wordpress.com/2009/05/29/anonymous-types-round-two/
最終的に、コードは次のようになります。
//create an anonymous type
var something = new {
name = "Mark",
age = 50
};
AnonymousType type = new AnonymousType(something);
//then access values by their property name and type
type.With((string name, int age) => {
Console.Write("{0} :: {1}", name, age);
});
//or just single values
int value = type.Get<int>("age");
DevExpressのxtraGridViewには、このGetRowCellDisplayText(int rowHandle、GridColumn column)のようなメソッドがあります。このメソッドでは、次のコードは匿名型からIDを返します。
var _selectedId = view.GetRowCellDisplayText(rowHandle, "Id");
これは「匿名オブジェクトのプロパティにアクセスするにはどうすればよいですか?」という質問に対する答えを提供しませんが、それでも問題の根本原因を解決しようとします。
DevXpressバージョン11.1でこれを試しましたが、この質問が最初に行われたのは約2。5年前であることがわかります。おそらく、質問の作成者が回避策を持っているか、自分で解決策を見つけた可能性があります。それでも、誰かを助けるために私はまだ答えています。
JaredParが正しく推測したように、GetRow()
の戻り値の型はobject
です。 DevExpressグリッドを使用する場合、次のように目的の値を抽出できます。
int clientId = (int)gridView.GetRowCellValue(rowHandle, "ClientId");
このアプローチには、前述の「ハッキーな匿名型キャスト」と同様の欠点があります。列を識別するためのマジックストリングと、オブジェクトからintへの型キャストが必要です。
次のような匿名型のプロパティをループできます。
var obj = new {someValue = "hello", otherValue = "world"};
foreach (var propertyInfo in obj.GetType().GetProperties() {
var name = propertyInfo.Name;
var value = propertyInfo.GetValue(obj, index: null);
...
}
これは間違っている可能性があります(十分なコードがない可能性があります)が、行にインデックスを付ける必要がないので、必要な列を選択しますか?または、「Id」が必要な列である場合は、次のようにする必要があります。
var selectedObject = view.GetRow(rowHandle);
_selectedId = selectedObject["Id"];
これは、データグリッドの列の内容を取得する方法です。列自体が匿名型の場合はわかりませんが、プリミティブ型の名前付き列を取得するだけの場合は、これで機能するはずです。
これがお役に立てば幸いです。別のリストを取得する必要があるインターフェイスリストを渡しています。最初に匿名型リストを取得し、次にそれを歩いてオブジェクトリストに転送します。
private List<StockSymbolResult> GetDistinctSymbolList( List<ICommonFields> l )
{
var DistinctList = (
from a
in l
orderby a.Symbol
select new
{
a.Symbol,
a.StockID
} ).Distinct();
StockSymbolResult ssr;
List<StockSymbolResult> rl = new List<StockSymbolResult>();
foreach ( var i in DistinctList )
{
// Symbol is a string and StockID is an int.
ssr = new StockSymbolResult( i.Symbol, i.StockID );
rl.Add( ssr );
}
return rl;
}
何をしているのかがわかっていて、コードが変更されたときにランタイムエラーが発生することを恐れていない場合は、行データをdynamic
としてキャストできます。
var data = view.GetRow(rowHandle) as dynamic;
int clientId = data.ClientID;
string clientName = data.ClientName;
int jobs = data.Jobs
コンパイル時の検証はありません。しかし、それはうまく機能するはずです。
var result = ((dynamic)DataGridView.Rows[rowNum].DataBoundItem).value;