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