您如何将字典 转换为字典 ?

问题描述 投票:3回答:5

假设我有:

public class Animal
{
    virtual public void Attack() {};
}
public class Lion : Animal
{
    public override void Attack() { base.Attack(); }
}
public class Boar : Animal
{
    public override void Attack() { base.Attack(); }
}

以及这两种动物的容器:

Dictionary<int, Lion> lions;
Dictionary<int, Boar> boars;

是否有一种方法可以转换“狮子”和“公猪”,以便我可以将它们传递给这样的函数?

void IterateTable(Dictionary<int, Animal> dictionary)
{
    foreach(var entry in dictionary)
        entry.Value.Attack();
}
c#
5个回答
6
投票

也许是这样?

void IterateTable<T>(Dictionary<int, T> dictionary)
    where T : Animal
{
    foreach(var entry in dictionary)
        entry.Value.Attack();
}

4
投票

您的代码按书面规定工作。当字典值中的动物调用其Attack()方法时,它将调用适当的动物特定方法。这称为covariance。您可以为字典提供比其签名所要求的更为具体的类型。

您可以按如下所示修改您的代码:

void Main()
{
    Dictionary<int, Animal> dictionary = new Dictionary<int, Animal>()
    {
        [1] = new Lion(),
        [2] = new Boar()
    };

    IterateTable(dictionary);
}

public class Animal
{
    virtual public void Attack() { Console.WriteLine("Default animal attack"); }
}
public class Lion : Animal
{
    public override void Attack() { Console.WriteLine("Lion attack"); }
}
public class Boar : Animal
{
    public override void Attack() { Console.WriteLine("Boar attack"); }
}

void IterateTable(Dictionary<int, Animal> dictionary)
{
    foreach (var entry in dictionary)
        entry.Value.Attack();
}

输出:

狮子攻击

野猪袭击


1
投票

问题是,如果您传入字典,则没有什么阻止IterateTable向其添加元素。那是个问题。由于IterateTable认为它是Dictionary<Animal>,因此可以添加“野猪”或“狮子”或两者。这显然是行不通的。

void IterateTable(Dictionary<int,Animal> dictionary)
{
    dictionary.Add(1, new Boar()); //This would fail if you'd passed in a dictionary of Lions
    dictionary.Add(2, new Lion()); //This would fail if you'd passed in a dictionary of Boars
}

由于IterateTable实际上不必在字典中添加任何元素,因此您可以更改其签名,以便它接受诸如IEnumerable<T>之类的只读对象。因为该接口不允许添加任何东西,所以它是合法的,并且编译错误也消失了。

void IterateTable(IEnumerable<Animal> dictionary)
{
    foreach (var entry in dictionary)
        entry.Attack();
}

现在您可以编写此代码,它将正常编译:

var lions = new Dictionary<int, Lion>();
var boars = new Dictionary<int, Boar>();
IterateTable(lions.Values);
IterateTable(boars.Values);

顺便说一下,这个概念叫做covariance,是理解泛型的一个非常重要的部分。


1
投票

A Dictionary<TKey,TValue>IEnumerable<KeyValuePair<TKey,TValue>>

所以,简单的方法是使用`ToDictionary(),只是在值选择器中上载值:

Dictionary<string,Lion> dict  = new Dictionary<string,Lion>( GetMeSomeLions() );

Dictionary<string,Animal> dictAnimals = dict.ToDictionary(
  kvp =>          kvp.Key,          // Key selector
  kvp => (Animal) kvp.Value // Value selector
);

0
投票

如果从以下位置更改容器:

Dictionary<int, Lion> lions;

Dictionary<int, Animal> lions;

不是初学者,那么我将按如下方式打电话:

IterateTable(lions.ToDictionary(
                k => k.Key,
                v => (Animal)v.Value)
            ));
© www.soinside.com 2019 - 2024. All rights reserved.