Reputation: 9701
I have a C# problem that has been bothering me for the past couple of days. I'll try to explain it based on an abstract description of what I am doing. Hope it is easy to follow. ;)
Let's say we have an interface
interface iFoo {
void a();
}
Further I have for example 2 classes that implement this interface and the method that is in it:
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"); }
}
Each class also provides an additional unique method - anotherMethodBar1() and anotherMethodBar2(). Now in my main() I want to create a list, which contains objects that implement my interface like this:
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()
}
}
}
}
}
As you can see I want to call each object's own (not included in the interface) method (based on the class we have anotherMethodBar1() or anotherMethodBar2(), which are NOT part of the interface). The question is - how do I do that? I'm new to C# and so far my experience had little to do with casting but right now I need it. Is this even done by using casting or is there another way? It is not possible to simply call the method
if(fooBarObjects[i].GetType() == typeof(bar1))
{
fooBarObjects[i].anotherMethodBar1();
}
because C# doesn't understand the exact type that lies underneath and thus the available methods/functions for this object are only the standard once plus my a()-method:
I really tried to find a solution but so far only the inverse has been asked quite often - list of objects to a list of interface conversion.
Thanks a lot and best regards!
Upvotes: 3
Views: 12166
Reputation: 9
Simply cast it :)
(fooBarObjects[i] as bar1).anotherMethodBar1();
Picking what you had
for(int i = 0; i < fooBarObjects.Count; i++)
{
if(fooBarObjects[i].GetType() == typeof(bar1))
(fooBarObjects[i] as bar1).anotherMethodBar1();
}
Upvotes: -1
Reputation: 120480
You can use the .OfType
extension method to extract items of a certain type:
var allTheBar1s = fooBarObjects.OfType<bar1>();
foreach(bar1 item in allTheBar1s)
{
//bar1 action
}
//...etc...
Of course this requires a second iteration for the bar2
items, but unless this is a hotspot, this doesn't really matter.
Perhaps preferable would be to use polymorphism and a single interface method to apply the action. This avoids any kind of requirement to test types.
interface IFoo
{
void DoSomething();
...
}
class bar1 : IFoo
{
public void DoSomething()
{
this.anotherMethodBar1();
}
....
}
class bar2 : IFoo
{
public void DoSomething()
{
this.anotherMethodBar2();
}
....
}
Now:
foreach(IFoo item in fooBarItems)
{
item.DoSomething();
}
Upvotes: 1
Reputation: 460158
You could use the as
operator to try-cast it to the type:
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();
}
}
This is the most readable and less error-prone way to cast.
Upvotes: 1
Reputation: 21485
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();
}
}
The key is the keyword is
which checks if the object is of type bar1
(or any type derived from bar1
) and the (type)object
syntax which casts the object to your specified type.
An alternative option is to use as
keyword which does the cast and returns null
if the cast cannot be done.
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();
}
}
}
The second option is considered to be recommended over the first because the runtime only has to do the type checking once (in the as
keyword) instead of twice (is
and ()
).
Upvotes: 9