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

本文关键字:转换 单个 元素 对象 列表 接口 | 更新日期: 2023-09-27 18:18:05

我有一个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"); }
}

每个类还提供了一个额外的唯一方法 - otherMethodBar1(( 和 otherMethodBar2((。现在在我的 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()
                }
            }
        }
    }
}

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

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

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

  • a((
  • 等于((
  • GetType((
  • GetHashCode((
  • ToString((

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

非常感谢和最好的问候!

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

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

您可以使用

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

这是最具可读性和不易出错的转换方式。

可以使用 .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();
}

只需将其转换为:)

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

挑选你拥有的东西

for(int i = 0; i < fooBarObjects.Count; i++)
{
   if(fooBarObjects[i].GetType() == typeof(bar1))
      (fooBarObjects[i] as bar1).anotherMethodBar1();
}