3

我有一个过去几天一直困扰我的 C# 问题。我将尝试根据对我正在做的事情的抽象描述来解释它。希望它很容易遵循。;)

假设我们有一个接口

interface iFoo {
   void a();
}

此外,我有例如 2 个实现此接口的类及其中的方法:

class bar1 : iFoo
{
   public void a() { Console.WriteLine("bar1"); }
   public void anotherMethodBar1() { Console.Write("I love "); }
}

class bar2 : iFoo
{
   public void a() { Console.WriteLine("bar2"); }
   public void anotherMethodBar2() { Console.Write("beer"); }
}

每个类还提供了一个额外的唯一方法 - anotherMethodBar1() 和 anotherMethodBar2()。现在在我的 main() 中,我想创建一个列表,其中包含实现我的接口的对象,如下所示:

namespace ExampleFooBar
{
    class Program
    {
        static void Main(string[] args)
        {
            List<iFoo> fooBarObjects = new List<iFoo>();
            fooBarObjects.Add(new bar1());
            fooBarObjects.Add(new bar2());

            for(int i = 0; i < fooBarObjects.Count; i++)
            {
                if(fooBarObjects[i].GetType() == typeof(bar1))
                {
                    //Cast element to bar1 and use anotherMethodBar1()
                }
                if(fooBarObjects[i].GetType() == typeof(bar2))
                {
                    //Cast element to bar2 and use anotherMethodBar2()
                }
            }
        }
    }
}

如您所见,我想调用每个对象自己的(不包含在接口中)方法(基于我们有 anotherMethodBar1() 或 anotherMethodBar2() 的类,它们不是接口的一部分)。问题是——我该怎么做?我是 C# 的新手,到目前为止,我的经验与铸造没什么关系,但现在我需要它。这甚至是通过使用铸造来完成的还是有其他方法?不能简单地调用方法

if(fooBarObjects[i].GetType() == typeof(bar1))
{
    fooBarObjects[i].anotherMethodBar1();
}

因为 C# 不理解底层的确切类型,因此该对象的可用方法/函数只是标准一次加上我的 a() 方法:

  • 一个()
  • 等于()
  • 获取类型()
  • 获取哈希码()
  • 字符串()

我真的试图找到一个解决方案,但到目前为止,只经常问到相反的问题 - 对象列表到接口转换列表。

非常感谢和最好的问候!

4

4 回答 4

8
        for(int i = 0; i < fooBarObjects.Count; i++)
        {
            if(fooBarObjects[i] is bar1)
            {
                ((bar1)fooBarObjects[i]).anotherMethodBar1();
            }
            else if (fooBarObjects[i] is bar2)
            {
                ((bar2)fooBarObjects[i]).anotherMethodBar2();
            }
        }

关键是is检查对象是否属于类型bar1(或从 派生的任何类型bar1)的(type)object关键字以及将对象转换为指定类型的语法。

另一种选择是使用执行强制转换并在无法完成强制转换时as返回的关键字。null

        for(int i = 0; i < fooBarObjects.Count; i++)
        {
            var b1 = fooBarObjects[i] as bar1;
            if  (b1 != null)
            {
                b1.anotherMethodBar1();
            }
            else
            {
                var b2 = fooBarObjects[i] as bar2;
                if (b2 != null)
                {
                    b2.anotherMethodBar2();
                }
            }
        }

第二个选项被认为比第一个更推荐,因为运行时只需要进行一次类型检查(在as关键字中)而不是两次(isand ())。

于 2013-06-12T11:00:11.793 回答
1

您可以使用.OfType扩展方法来提取某种类型的项目:

var allTheBar1s = fooBarObjects.OfType<bar1>();
foreach(bar1 item in allTheBar1s)
{
    //bar1 action
}
//...etc...

当然,这需要对bar2项目进行第二次迭代,但除非这是一个热点,否则这并不重要。

也许更可取的是使用多态性和单个接口方法来应用该操作。这避免了对测试类型的任何要求。

interface IFoo
{
    void DoSomething();
    ...
}
class bar1 : IFoo
{
    public void DoSomething()
    {
         this.anotherMethodBar1();
    }
    ....
}
class bar2 : IFoo
{
    public void DoSomething()
    {
         this.anotherMethodBar2();
    }
    ....
}

现在:

foreach(IFoo item in fooBarItems)
{
    item.DoSomething();
}
于 2013-06-12T11:08:39.170 回答
1

您可以使用as运算符尝试将其转换为类型:

for (int i = 0; i < fooBarObjects.Count; i++)
{
    var bar1 = fooBarObjects[i] as Bar1;
    if (bar1 != null)
        bar1.anotherMethodBar1();
    else {
        var bar2 = fooBarObjects[i] as Bar2;
        if (bar2 != null)
            bar2.anotherMethodBar2();
    }
}

这是最易读且不易出错的转换方式。

于 2013-06-12T11:05:04.967 回答
-1

只需投射它:)

(fooBarObjects[i] as bar1).anotherMethodBar1();

挑选你所拥有的

for(int i = 0; i < fooBarObjects.Count; i++)
{
   if(fooBarObjects[i].GetType() == typeof(bar1))
      (fooBarObjects[i] as bar1).anotherMethodBar1();
}
于 2013-06-12T11:17:10.647 回答