Подтвердить что ты не робот

Невозможно присвоить null анонимному свойству массива типов

У меня есть любой массив объектов (Pilot) с свойством (Hanger), который может быть нулевым, который сам имеет свойство (List<Plane>). В целях тестирования я хочу упростить и "сгладить" это анонимному объекту со свойствами PilotName (string) и Planes (array), но не уверен, как обрабатывать свойство null Hanger или пустой PlanesList,

(Почему анонимные объекты? Поскольку объекты API, которые я тестирую, доступны только для чтения, и я хочу, чтобы тест был "декларативным": автономным, простым и читаемым... но я открыт для других предложений. Также я пытаюсь узнать больше о 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 ошибок с,

Невозможно назначить свойство анонимного типа, но признать, что основная проблема может заключаться в том, что использование null in actual использует null не лучший подход в первую очередь.

Любые идеи о том, как назначить нулевой массив в expected или использовать другой подход, чем null в actual?

4b9b3361

Ответ 1

Происходит две вещи:

Во-первых, когда вы создаете экземпляр анонимного типа с помощью new { Name = Value}, чтобы построить тип, компилятор должен уметь выработать тип Value. Просто null сам по себе не имеет типа, поэтому компилятор не знал бы, какой тип должен предоставить ваш член Planes.

Теперь, если вы использовали именованный тип для значения, вы могли бы просто сказать (type)null и сделать это, НО, потому что вам нужен массив другого анонимного типа, нет способа ссылаться на него (это анонимно!),

Итак, как вы получаете null в виде массива анонимного типа? Ну, спецификация С# гарантирует, что анонимные типы с членами имеют одинаковые имена и типы (в том же порядке!) унифицированы; т.е. если мы скажем

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

то a и b имеют тот же тип. Мы можем использовать этот факт, чтобы получить подходящий тип null таким образом:

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

Это не очень хорошо, но он работает - теперь array имеет правильный тип, но null значение. Таким образом, это компилируется:

        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" }
                                                    }
                                   }
                           };

Ответ 2

Вы должны использовать типизированный null:

(List<Plane>)null

или

(Plane[])null

В противном случае компилятор не знает, какой тип вы хотите, чтобы член анонимного типа был.

Обновление Как справедливо указал @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);

Ответ 3

Просто используйте default(Plane[]) вместо null.