C#接口对象列表 - 转换单个元素

时间:2013-06-12 10:57:30

标签: c# list methods interface casting

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

假设我们有一个界面

interface iFoo {
   void a();
}

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

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

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

是不可能的
if(fooBarObjects[i].GetType() == typeof(bar1))
{
    fooBarObjects[i].anotherMethodBar1();
}

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

  • 一个()
  • 等于()
  • 的GetType()
  • GetHashCode()方法
  • 的ToString()

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

非常感谢和最诚挚的问候!

4 个答案:

答案 0 :(得分:5)

        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关键字中)而不是两次(is() )。

答案 1 :(得分:1)

您可以使用as operator尝试将其投射到类型:

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

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

答案 2 :(得分: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();
}

答案 3 :(得分:-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();
}