我在使用字典和泛型在 C# 中创建嵌套对象结构时遇到一些问题(我使用的是 Visual Studio、.NET Framework 4.6+)
主要问题是 C# 字典中缺乏协变性。
我必须在 C# 中创建这个简单的(JSON 可序列化/反序列化)对象结构。我尝试用动物来解释......
public class AnimalCatalog
{
public Dictionary<string, Animal> AnimalsDict { get; set; } // key is the species name
}
public class Animal // base class
{
public string Species { get; set; } // univocal
public bool CanFly { get; set; }
public Dictionary<string, GenericPaw> PawsDict { get; set; } // each animal has a different type and a different number of paws
}
public class GenericPaw // base class
{
public int FingerNumber { get; set; } // number of finger in each paw
}
public class Cat : Animal // derived class
{
public void meow() // only cats says 'meow'
{...}
}
public class CatPaw : GenericPaw // derived class
{
public void scratch() // cats paws could scratch something :) but not all the animals paws could
{...}
}
我使用 C# 泛型实现了这个结构,因为 Cat 有一个 CatPaws 字典,而不是泛型 Paws :P。这是我的建议。
public class AnimalCatalog<T,V> where T : Animal<V> where V : GenericPaw
{
public Dictionary<string, T> AnimalsDict { get; set; } = new Dictionary<string, T>(); // key is the species name
}
public class Animal<T> where T : GenericPaw // base class
{
public string Species { get; set; } // univocal
public bool CanFly { get; set; }
public Dictionary<string, T> PawsDict { get; set; } // each animal has a different type and a different number of paws
}
public class GenericPaw // base class
{
public string PawName { get; set; } // univocal
public int FingerNumber { get; set; } // number of finger in each paw
}
public class Cat<T> : Animal<T> where T : CatPaw // derived class
{
public void meow() // only cats says 'meow'
{...}
}
public class CatPaw : GenericPaw // derived class
{
public void scratch() // cats paws could scratch something :) but not all the animals paws could
{...}
}
让我们使用创建的类</p>
Cat<CatPaw> Kitty = new Cat<CatPaw>(); // create a cat
CatPaw KittyFirstPaw = new CatPaw(); // create the 1st cat's paw
Kitty.PawsDict.Add(KittyFirstPaw.PawName, KittyFirstPaw); // add the paw to the dict
AnimalCatalog<Animal<GenericPaw>,GenericPaw> ZooCatalog = new AnimalCatalog<Animal<GenericPaw>,GenericPaw>(); // create a catalog of animals
Animal<GenericPaw> GenericAnimal = Kitty; <-- doens't compile (can't convert derived to base class)
AnimalCatalog.AnimalsDict.Add(GenericAnimal.Species, GenericAnimal);
我还尝试使用接口(interface)而不是基类,使用 out 关键字将 T 指定为协变类型,但它不起作用,因为我无法在字典中使用协变类型...
非常感谢任何帮助:) 斯特凡诺
最佳答案
您无法转换Cat<CatPaw>
至Animal<GenericPow>
,因为这样您就可以添加不同类型的 GenericPaw
进入它的字典(例如 DogPaw
),猫不会欣赏这一点。
这只是一个问题,因为您可以在字典中插入新值,因此似乎可以通过使用 IReadOnlyDictionary
来解决它,但不幸的是,由于 this question 中描述的技术问题,该值也不是协变的。 .
顺便说一句,有没有原因 Cat
也是通用的吗?
public class Cat<T> : Animal<T> where T : CatPaw
如果您想创建一只只能拥有源自CatPaw
的特定爪子的猫,这将很有用。 。如果没有,这可能会变成:
public class Cat : Animal<CatPaw>
AnimalCatalog
似乎也不必要地复杂。如果您只需要 Animal
的动物目录,它可以简化为只有一个通用参数:
public class AnimalCatalog<TPaw> where TPaw : GenericPaw
{
public Dictionary<string, Animal<TPaw>> AnimalsDict { get; set; }
}
如果您只需要 AnimalCatalog<GenericPaw>
,你也可以去掉这个参数。但这个目录仍然不是很有用,因为您无法转换 Animal<CatPaw>
至Animal<GenericPaw>
.
为了解决这个问题,您可以创建 IAnimal<out TPaw>
的协变接口(interface)具有 Animal
的所有属性但除了字典之外,您还可以将爪子公开为 IEnumerable<TPaw> Paws
如果您需要字典查找,可以使用以下方法:TPaw GetPaw(string pawName)
。这些将使用字典来实现。然后就可以转换 Cat
(这是 Animal<CatPaw>
,因此也是 IAnimal<CatPaw>
)到 IAnimal<GenericPaw>
。您的动物目录将包含 IAnimal<GenericPaw>
.
关于c# - 使用字典和泛型创建嵌套的 JSON 可序列化对象结构时,.NET 中的 C# 协方差存在问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48060913/