web-dev-qa-db-ja.com

配列型の匿名プロパティにnullを割り当てることはできません

Pilot)プロパティを持つ(Hanger)オブジェクトの配列があり、それはnullである可能性があり、それ自体に(List<Plane>)プロパティ。テストのために、これを単純化して、プロパティPilotName(string)およびPlanes(array)を持つ匿名オブジェクトに「フラット化」したいが、null Hangerプロパティまたは空のPlanesList

(なぜ匿名オブジェクトなのですか?私がテストしているAPIのオブジェクトは読み取り専用であり、テストを「宣言的」にしたいので、自己完結型でシンプルで読み取り可能です...しかし、他の提案にもオープンです。 m LINQの詳細を学習しようとしている。)

class Pilot
{
    public string Name;
    public Hanger Hanger;
}

class Hanger
{
    public string Name;
    public List<Plane> PlaneList;
}

class Plane
{
    public string Name;
}

[TestFixture]
class General
{
    [Test]
    public void Test()
    {
        var pilots = new Pilot[]
        {
            new Pilot() { Name = "Higgins" },
            new Pilot()
            {
                Name = "Jones", Hanger = new Hanger()
                {
                    Name = "Area 51",
                    PlaneList = new List<Plane>()
                    {
                        new Plane { Name = "B-52" },
                        new Plane { Name = "F-14" }
                    }
                }
            }
        };

        var actual = pilots.Select(p => new
        {
            PilotName = p.Name,
            Planes = (p.Hanger == null || p.Hanger.PlaneList.Count == 0) ? null : p.Hanger.PlaneList.Select(h => ne
            {
                PlaneName = h.Name
            }).ToArray()
        }).ToArray();

        var expected = new[] {
            new { PilotName = "Higgins", Planes = null },
            new
            {
                PilotName = "Jones",
                Planes = new[] {
                    new { PlaneName = "B-52" },
                    new { PlaneName = "F-14" }
                }
            }
        };

        Assert.That(actual, Is.EqualTo(expected));
    }

当面の問題は、行expected... Planes = nullエラー、

匿名タイプのプロパティに割り当てることはできませんが、根本的な問題はnullactualを使用することはnullを使用することが最初から最善のアプローチではないことを認めています。

expectedのnull配列を割り当てる方法、またはnullactualとは異なるアプローチを取る方法はありますか?

29
petemoloy

発生していることが2つあります。

まず、new { Name = Value}を使用して匿名型のインスタンスを構築する場合、型を構築するには、コンパイラがValueの-​​typeを計算できる必要があります。 null自体には型がないので、コンパイラーはPlanesメンバーにどの型を与えるかわかりません。

値に名前付きの型を使用している場合、(type)nullと言うだけで完了しますが、別の匿名型の配列が必要なため、する方法はありません。への参照is(それは匿名です!).

それでは、匿名型の配列としてnullをどのように入力しますか?まあ、C#仕様では、同じ名前と型(同じ順序で!)のメンバーを持つ匿名型がnifiedであることを保証しています。つまり、

var a = new { Foo = "Bar" };
var b = new { Foo = "Baz" };

次に、abには同じタイプがあります。この事実を使用して、適切に型付けされたnullを取得できます。

var array = (new[] { new { PlaneName = "" } });
array = null;

それはきれいではありませんが、動作します-arrayは正しいtypeを持っていますが、nullvalueを持っています。したがって、これはコンパイルされます:

        var array = new[] { new { PlaneName = "" } };
        array = null;

        var expected = new[]
                           {
                               new
                                   {
                                       PilotName = "Higgins",
                                       Planes = array
                                   },
                               new
                                   {
                                       PilotName = "Higgins",
                                       Planes = new[]
                                                    {
                                                        new { PlaneName = "B-52" },
                                                        new { PlaneName = "F-14" }
                                                    }
                                   }
                           };
36
AakashM

typednullを使用する必要があります:

(List<Plane>)null

または

(Plane[])null

それ以外の場合、コンパイラーは、匿名型のメンバーにしたい型を認識しません。

pdate @AakashMが正しく指摘したように、これにより、nullを匿名メンバーに割り当てるという問題が解決しますが、実際にはコンパイルされません-コンパイルした場合、許可されません。これらのメンバーを参照してください。

修正はこれを行うことです(残念ながら、nullと匿名のPlanesの両方の配列をキャストする必要があります:

var expected = new[] {
  new { 
          PilotName = "Higgins", 
          Planes = (IEnumerable)null
      },
  new {
          PilotName = "Higgins", 
          Planes = (IEnumerable)new [] {
                              new { PlaneName = "B-52" },
                              new { PlaneName = "F-14" } 
                          }
      }
};

したがって、メンバータイプとしてIEnumerableを使用します。 IEnumerable<object>を使用することもできますが、効果はどちらの方法でも同じです。

または-IEnumerable<dynamic>を一般的なタイプとして使用できます-これによりこれを行うことができます:

Assert.AreEqual("B-52", expected[1].Planes.First().PlaneName);
50
Andras Zoltan

nullの代わりにdefault(Plane[])を使用してください。

8