接口对象的 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((
我真的试图找到一个解决方案,但到目前为止,只有相反的问题经常被问到——对象列表到接口转换列表。
非常感谢和最好的问候!
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();
}