MVCコントローラーでテストする匿名型を返す関数があります。
public JsonResult Foo()
{
var data = new
{
details = "something",
more = "More"
};
return Json(data);
}
Foo関数から取得したデータを確認したいのですが、今行っているのは、データ型を取得し、リフレクションを使用してそのプロパティ値を取得することです。
[Test]
public void TestOne()
{
var data = _controller.Foo().Data;
var details = data.GetType().GetProperty("details").GetValue(data, null);
var more = data.GetType().GetProperty("more").GetValue(data, null);
Assert.AreEquals("something", details);
Assert.AreEquals("More", more);
}
匿名プロパティをチェックするこれに似た簡単な方法はありますか?
[Test]
public void TestTwo()
{
var data = (dynamic) _controller.Foo().Data;
var details = data.details; // RunTimeBinderException object does not contain definition for details
var more = data.more;
Assert.AreEquals("something", details);
Assert.AreEquals("More", more);
}
匿名オブジェクトはinternal
です。つまり、それらのメンバーは、それらを宣言するアセンブリの外部では非常に制限されています。 dynamic
はアクセシビリティを尊重するため、これらのメンバーを見ることができないふりをします。呼び出しサイトが同じアセンブリ内にあった場合、それが機能することを期待しています。
リフレクションコードはmemberアクセシビリティを尊重しますが、型のアクセシビリティをバイパスします-したがって機能します。
つまり、いいえ。
このブログには有効な回答がありました: http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html -ありがとう@ Jorge-Fioranelli。
public static class DynamicExtensions {
public static dynamic ToDynamic(this object value) {
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
return expando as ExpandoObject;
}
}
匿名型は.NETの通常の静的型であり、名前を付けないだけです(ただし、コンパイラは名前を付けます)。これがdynamic
へのキャストが機能しない理由です。ただし、Foo()
を制御できる場合は、匿名の代わりにdynamic
オブジェクトを作成して返すことができ、コードが機能します。これでうまくいくはずです:
dynamic JsonResult Foo() {
dynamic data = new ExpandoObject();
data.details = "something";
data.mode = "More";
return Json(data);
}
@TrueWillおよび@Marc Gravellが示唆したように、これらも参照 このブログ投稿
これは単体テスト用なので、InternalsVisibleToを使用できます。匿名型は内部である、C#4.0動的注意に注意してください!匿名オブジェクトが内部にあることを指摘してくれた@MarcGravellに感謝します!
結論:あるアセンブリから別のアセンブリに匿名オブジェクトを共有する場合は、[Assembly: InternalsVisibleTo("foo")]
マッピングをセットアップします。 OPの場合は、test projectを参照して、MVCコントローラープロジェクトでこれを設定するだけです。私の特定のケースでは、その逆です(私のテストプロジェクトから "量産コード"プロジェクトに匿名オブジェクトを渡しているため)。
この「他のプロジェクト」で使用できる最も簡単な方法は、確実にdynamic
にキャストしてから、通常のようにプロパティを使用することです。動作しますが、問題はありません。
つまり、最終的には、Marc Gravellの答えは少し間違っているように感じます。これは明らかにできる
(iff問題のプロジェクトはユーザーが変更できるため、InternalsVisibleToマッピングを適宜設定できます。これにより、その他の理由による問題)。
NewtonSoftまたはAsp.net MVCライブラリを使用できます。
var data = Json.Decode(Json.Encode(_controller.Foo().Data));
var data=JsonConvert.DeserializeObject<Dictionary<string,object>>(JsonConvert.SerializeObject((_controller.Foo().Data))