web-dev-qa-db-fra.com

Impossible d'affecter null à une propriété anonyme de type tableau

J'ai un tableau d'objets (Pilot) avec une propriété (Hanger), qui peut être nulle, qui a elle-même une (List<Plane>) propriété. À des fins de test, je veux simplifier et "aplatir" cela en un objet anonyme avec les propriétés PilotName (chaîne) et Planes (tableau) mais je ne sais pas comment gérer un null Hanger ou un PlanesList vide.

(Pourquoi des objets anonymes? Parce que les objets de l'API que je teste sont en lecture seule et je veux que le test soit "déclaratif": autonome, simple et lisible ... mais je suis ouvert à d'autres suggestions. Aussi je " j'essaie d'en savoir plus sur LINQ.)

exemple

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

Le problème immédiat est que la ligne expected... Planes = null erreurs avec,

Impossible d'affecter à une propriété de type anonyme mais admettez que le problème sous-jacent peut être que l'utilisation de null dans actual utilise null n'est pas la meilleure approche en premier lieu.

Avez-vous des idées sur la façon d'affecter le tableau nul dans expected ou d'adopter une approche différente de null dans actual?

29
petemoloy

Il se passe deux choses:

Premièrement, lorsque vous construisez une instance d'un type anonyme à l'aide de new { Name = Value}, afin de construire le type, le compilateur doit être capable de déterminer type de Value. Juste null seul n'a pas de type, donc le compilateur ne saurait pas quel type donner à votre membre Planes.

Maintenant, si vous utilisez un type nommé pour la valeur, vous pouvez simplement dire (type)null et c'est fait, MAIS parce que vous voulez un tableau d'un autre type anonyme, il n'y a aucun moyen de se référer à is (c'est anonyme!).

Alors, comment obtenez-vous null tapé en tant que tableau d'un type anonyme? Eh bien, la spécification C # garantit que les types anonymes avec des membres ayant les mêmes noms et types (dans le même ordre!) Sont nifiés; c'est-à-dire, si nous disons

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

alors a et b ont le même type. Nous pouvons utiliser ce fait pour obtenir notre null correctement typé:

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

Ce n'est pas joli mais cela fonctionne - maintenant array a le droit type mais un nullvaleur. Donc, cela compile:

        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

Vous devez utiliser un tapé null :

(List<Plane>)null

Ou

(Plane[])null

Sinon, le compilateur n'a aucune idée de quel type vous voulez que le membre du type anonyme soit.

pdate Comme @AakashM l'a souligné à juste titre - cela résout votre problème d'attribution d'un null à un membre anonyme - mais ne compile pas réellement - et s'il le faisait, il ne permettrait pas vous référer à ces membres.

Un correctif serait de faire cela (malheureusement, le tableau null et le tableau Planes anonyme devront être castés:

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

Utilisez donc IEnumerable comme type de membre. Vous pouvez également utiliser IEnumerable<object> mais l'effet sera le même dans les deux cas.

Ou - vous pouvez utiliser IEnumerable<dynamic> comme type commun - cela vous permettrait de faire ceci:

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

Utilisez simplement default(Plane[]) au lieu de null.

8
Viacheslav Ivanov