◆ Dictionary<string, object> で JSON 風な扱いするなら 匿名型を扱ったほうがいい
◆ 定義やアクセスのときに [""] 書かなくて済む
◆ DIctionary<string, object> も書かなくて済む
◆ メソッドまたぐときは dynamic 型で受け渡し
  ◆ コンパイル時にエラーわからないのは Dicitonary も一緒
◆ 要素が少ないなら有効な一部を除いて静的解析できる方法もある
  ◆ 少ないならタプルでいいかもだけど

JSON みたいに複数のデータを持ちたくてタプルにしてはちょっと数が多い時 key に string を value に object を指定した Dictionary を使うことが多いです
あちこちで使いまわすものでもなく 頻繁に構造変わるものだとちゃんと class を定義するのは手間がかかります
ですが Dictionary だと動的言語のオブジェクトのような使い勝手が実現できます

こういうデータを返すメソッドを
return new Dictionary<string, object>{
["abcd"] = 100,
["efgh"] = "text",
["ijkl"] = 200,
["mnop"] = false,
};

こんな風に使えます
var data = getValues();

var val = (int)data["abcd"];
var val2 = data["efgh"].ToString();

でもこれって定義のときもアクセスするときもキーには [""] を使わないといけません
数が多くなると書くのが地味にめんどうです

JavaScript だと ["x"] でも .x でもアクセスできて基本 .x 形式です
return {
foo: "1",
bar: false
}
var data = getValues()
var val = data["foo"]
var val2 = data.bar.toString()
普段 JavaScript を書いてるとやっぱり .x で書きたいです


考えてみれば dynamic 型で匿名型オブジェクトを使うとそういうことができます
dynamic を避ける理由の 「静的解析でエラーに気づけない」 というのは Dictionary も一緒です
それに Dictionary でも型がバラバラなので value 側は object としていて使うタイミングでキャストしています
こういう使い方だと dynamic とそう変わらず dynamic にしてもデメリットは特になさそうです

あえてあげるならプロパティ名にできない記号が使えません
でもたいていの場合ってプロパティに使える文字なので特に困りません

dynamic+匿名型を使うとこうなります
return new {
abcd = 100,
efgh = "text",
ijkl = 200,
mnop = false,
}
var data = getValues();

var val = (int)data.abcd;
var val2 = data.efgh.ToString();

Dictionary 使うときの半分くらいが string->object 型なので Dictionary のめんどくささが一気に減りました