私は何か間違ったことをしていますか、または次のコードは本当に不可能ですか?
dynamic x = new ExpandoObject { Foo = 12, Bar = "twelve" };
これが本当に不可能な場合、2つのプロパティを持つExpandoObjectをインスタンス化する別の1行の方法はありますか?
なぜC#チームは、通常のオブジェクト、匿名オブジェクト、および列挙型/リストの場合と同じ初期化構文を許可しないことを選択するのですか?
更新
パール愛好家にC#のクールで新しい動的な機能を見せようとしていたので、この質問をしましたが、ExpandoObject
の論理的なインスタンス化だと思っていたことができずに行き詰まりました。ハンスパッサントの回答のおかげで、ExpandoObject
はこの仕事には不適切なツールだったことがわかりました。私の本当の目標は、C#の動的機能を使用して、メソッドから2つの名前付きの値を返すことでした。 Hansが指摘するように、dynamic
キーワードはこれに最適です。これを行うために、ExpandoObject
とそのオーバーヘッドをすべて必要としませんでした。
したがって、メソッドから名前付きの値のペアを返す必要があり、型の安全性、Intellisense、リファクタリング、またはパフォーマンスを気にしない場合、これは非常にうまく機能します。
public dynamic CreateFooBar()
{
return new { Foo = 42, Bar = "Hello" };
}
使用法:
dynamic fooBar = CreateFooBar();
var foo = fooBar.Foo;
var bar = fooBar.Bar;
私は何か間違ったことをしていますか、または次のコードは本当に不可能ですか?
それは本当に不可能です。代入演算子の左側にあるものは、コンパイル時に既知のプロパティまたはフィールドでなければなりません。明らかに、expandoオブジェクトの場合はそうではありません。
なぜC#チームは、通常のオブジェクト、匿名オブジェクト、および列挙型/リストの場合と同じ初期化構文を許可しないことを選択するのですか?
質問の言い方は論理的な誤りを示しています。機能はデフォルトでは実装されておらず、悪い考えだと思うので、ほとんどすべての機能を許可せずに走り回っています。機能はデフォルトでnimplementedであり、機能するためにはimplementedである必要があります。
機能を実装する最初のステップは、誰かが最初にそれを考えなければならないということです。私の知る限り、私たちはそうしませんでした。特に、2006年にオブジェクト初期化子を設計する人が2010年に言語に「動的」を追加し、それに応じて機能を設計することを知るのは非常に困難でした。機能は常に前向きに移動する設計者によって設計され、後向きに移動することはありません。私たちは過去を覚えているだけで、未来は覚えていません。
とにかく、それは素晴らしいアイデアなので、共有していただきありがとうございます。誰かがそれを考えたので、次のステップに取り掛かることができます。たとえば、限られた予算を費やすことができる最良のアイデアであるかどうかを決定し、それを設計し、仕様を記述し、実装し、テストし、文書化し、顧客に発送します。
それがすぐに起こるとは思いません。先週ビルドで発表した非同期とWinRTのビジネス全体で少し忙しいです。
ExpandoObjectよりも優れたマウストラップがあります。 dynamicキーワードは、aplombを使用して匿名型を処理します。
class Program {
static void Main(string[] args) {
dynamic x = new { Foo = 12, Bar = "twelve" };
Display(x);
}
static void Display(dynamic x) {
Console.WriteLine(x.Foo);
Console.WriteLine(x.Bar);
}
}
不幸な問題の1つは、C#コンパイラがメンバーにinternalアクセスのみを与える匿名型を生成することです。つまり、別のアセンブリのメンバーにアクセスしようとすると、ランタイムエラーが発生します。残念。
C#v7では大幅に改善された a Tuple を検討してください。
Dynamitey(オープンソースPCLであり、nugetにあります)には、インライン展開可能な initializing expandos の構文があります。
//using Dynamitey.DynamicObjects
var x = Build<ExpandoObject>.NewObject(Foo:12, Bar:"twelve");
私のために働いた1つの回避策は、Yan Cui( source )によるこのToExpando()
拡張メソッドです:
public static class DictionaryExtensionMethods
{
/// <summary>
/// Extension method that turns a dictionary of string and object to an ExpandoObject
/// </summary>
public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary)
{
var expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>) expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>)
{
var expandoValue = ((IDictionary<string, object>) kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection) kvp.Value)
{
if (item is IDictionary<string, object>)
{
var expandoItem = ((IDictionary<string, object>) item).ToExpando();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp);
}
}
return expando;
}
}
使用例:
public const string XEntry = "ifXEntry";
public static readonly dynamic XEntryItems = new Dictionary<string, object>
{
{ "Name", XEntry + ".1" },
{ "InMulticastPkts", XEntry + ".2" },
{ "InBroadcastPkts", XEntry + ".3" },
{ "OutMulticastPkts", XEntry + ".4" },
{ "OutBroadcastPkts", XEntry + ".5" },
{ "HCInOctets", XEntry + ".6" },
{ "HCInUcastPkts", XEntry + ".7" },
{ "HCInMulticastPkts", XEntry + ".8" },
{ "HCInBroadcastPkts", XEntry + ".9" },
{ "HCOutOctets", XEntry + ".10" },
{ "HCOutUcastPkts", XEntry + ".11" },
{ "HCOutMulticastPkts", XEntry + ".12" },
{ "HCOutBroadcastPkts", XEntry + ".13" },
{ "LinkUpDownTrapEnable", XEntry + ".14" },
{ "HighSpeed", XEntry + ".15" },
{ "PromiscuousMode", XEntry + ".16" },
{ "ConnectorPresent", XEntry + ".17" },
{ "Alias", XEntry + ".18" },
{ "CounterDiscontinuityTime", XEntry + ".19" },
}.ToExpando();
次に、XEntryItems.Name
などのプロパティを使用できます。
PS:ExpandoObjectsのオブジェクト初期化子をサポートするには、投票してください ここ 。
Getおよびsetterのプロパティがすでにあるため、この種の初期化構文は可能です。 expandoオブジェクトでは、私が知ることのできるプロパティはまだありません。
これを行うはるかに簡単な方法:
Func<Dictionary<string, object>, ExpandoObject> parse = dict =>
{
var expando = new ExpandoObject();
foreach (KeyValuePair<string, object> entry in dict)
{
expando.Add(entry.Key, entry.Value);
}
return expando;
};
次に、解析関数を呼び出し、辞書をパラメーターとして渡します。もちろん、これは関数の代わりにメソッドに実装できます。