Get type and value of a MemberInfo m that in fact is a true bool?

P

per9000

Hi all,

I have a question I am unable solve.

I have an inheritance graph like this:
// CAR ----- MUSICAR ---- NICECAR
// \ \
// \ +------ OLDCAR
// \
// +---- HOMEMADECAR

All originate from Car. In musiCar I introduce "public bool hasStereo"
that I can assess with a cast and the test
bool mightHaveStereo = myCar.GetType().IsSubclassOf(typeof(musiCar));
(is this the best way test that BTW?)

Now I "want" another class that does not derive from musiCar but that
has an identical member hasStereo. I reach it and I can print it on
the console. I see that it is a bool and that it has the "correct"
name by using the following snippet:

Type T = myCar.GetType();
MemberInfo[] MIF = T.GetMembers();

foreach (MemberInfo m in MIF)
{
if (m.Name == "hasStereo" && T != typeof(niceCar))
{
Console.WriteLine(" - '{0}' : '{1}' ", m.Name, m);
}
}
}

Is there any way to get the value of myCar? I was hoping on something
like this:
((T) myCar).m;
or
if (m.isBool) myBool = ((bool)m);

See below for the complete example.

Thanks,
Per

Home: http://www.pererikstrandberg.se/blog/ .
Optimization in .NET: http://tomopt.com/tomnet/ .

-------------------------
using System;
using System.Reflection;

class Program
{
//
// Inheritance diagram
//
// CAR ----- MUSICAR ---- NICECAR
// \ \
// \ +------ OLDCAR
// \
// +---- HOMEMADECAR


// base class
public abstract class Car
{
public string nickname;
public string color;
public int miles;
}

// class for a car that might have a stereo
public abstract class musiCar : Car
{
public bool hasStereo;
}

// inherited class
public class niceCar : musiCar
{
public bool hasMP314Player;
}

// inherited class
public class oldCar : musiCar
{
public int age;
}

// car that is only related to the base class car
public class homeMadeCar : Car
{
public bool hasStereo;
public bool isEpa;
}

public static void displayCar(Car myCar)
{
Console.WriteLine("The {0} car...", myCar.color);
Console.WriteLine(" - is called '{0}'", myCar.nickname);
Console.WriteLine(" - has run for '{0}' miles", myCar.miles);

// is it a musicar?
if (myCar.GetType().IsSubclassOf(typeof(musiCar)))
{
if (((musiCar)myCar).hasStereo)
Console.WriteLine(" - has a stero");
else
Console.WriteLine(" - has no stero");

// is it an old car?
if (myCar.GetType() == typeof(oldCar))
{
Console.WriteLine(" - is {0} years old",
((oldCar)myCar).age);
}

// is it a nice car?
if (myCar.GetType() == typeof(niceCar))
{
if (((niceCar)myCar).hasMP314Player)
Console.WriteLine(" - has an MP314 player");
else
Console.WriteLine(" - has no MP314 player");
}
}

// what if it is some other class that also might have a stereo
Type T = myCar.GetType();
MemberInfo[] MIF = T.GetMembers();

foreach (MemberInfo m in MIF)
{
if (m.Name == "hasStereo" && T != typeof(niceCar))
{
Console.WriteLine(" - '{0}' : '{1}' ", m.Name, m);
}
}
}

static void Main(string[] args)
{

oldCar c1 = new oldCar();
c1.age = 25;
c1.color = "beige";
c1.hasStereo = false;
c1.miles = int.MaxValue / 2;
c1.nickname = "ugly betty";

niceCar c2 = new niceCar();
c2.color = "light blue metallic";
c2.hasMP314Player = true;
c2.hasStereo = c2.hasMP314Player;
c2.miles = 1337;
c2.nickname = "Turing the Tempest";

homeMadeCar c3 = new homeMadeCar();
c3.color = "black";
c3.hasStereo = true;
c3.isEpa = true;
c3.miles = 555;
c3.nickname = "KB::p_WAGON";

Console.WriteLine("CAR 1");
displayCar(c1);

Console.WriteLine("CAR 2");
displayCar(c2);

Console.WriteLine("\"CAR\" 3");
displayCar(c3);

}
}
 
P

per9000

BTW; the out put is:

C:\temp>dynamic_cast.exe
CAR 1
The beige car...
- is called 'ugly betty'
- has run for '1073741823' miles
- has no stero
- is 25 years old
- 'hasStereo' : 'Boolean hasStereo'
CAR 2
The light blue metallic car...
- is called 'Turing the Tempest'
- has run for '1337' miles
- has a stero
- has an MP314 player
"CAR" 3
The black car...
- is called 'KB::p_WAGON'
- has run for '555' miles
- 'hasStereo' : 'Boolean hasStereo'

-----------------

Per

Home: http://www.pererikstrandberg.se/blog/ .
Optimization in .NET: http://tomopt.com/tomnet/ .
 
J

Jon Skeet [C# MVP]

per9000 said:
Hi all,

I have a question I am unable solve.

I have an inheritance graph like this:
// CAR ----- MUSICAR ---- NICECAR
// \ \
// \ +------ OLDCAR
// \
// +---- HOMEMADECAR

All originate from Car. In musiCar I introduce "public bool hasStereo"
that I can assess with a cast and the test
bool mightHaveStereo = myCar.GetType().IsSubclassOf(typeof(musiCar));
(is this the best way test that BTW?)

No, you just need:

bool mightHaveStereo = (myCar is musiCar);
Now I "want" another class that does not derive from musiCar but that
has an identical member hasStereo. I reach it and I can print it on
the console.

It would be better to have an interface which both classes implemented,
so you didn't need to use reflection...
I see that it is a bool and that it has the "correct"
name by using the following snippet:

Type T = myCar.GetType();
MemberInfo[] MIF = T.GetMembers();

foreach (MemberInfo m in MIF)
{
if (m.Name == "hasStereo" && T != typeof(niceCar))
{
Console.WriteLine(" - '{0}' : '{1}' ", m.Name, m);
}
}
}

Why don't you just use Type.GetMethod() or Type.GetProperty()?
Is there any way to get the value of myCar? I was hoping on something
like this:
((T) myCar).m;
or
if (m.isBool) myBool = ((bool)m);

It depends what kind of member it is - if it's a method, use
MethodInfo.Invoke. If it's a property, use PropertyInfo.GetValue.

As I say, it would be better not to use reflection in the first
place...
 
P

per9000

Thanks Jon,

you pushed me in the right direction.

The testing for a stereo now looks like this:

// what if it is some other class that also might have a stereo
if (!(myCar is musiCar))
{
try
{
Type T = myCar.GetType();
FieldInfo field = T.GetField("hasStereo");

if ((bool)field.GetValue(myCar))
Console.WriteLine(" - has a stereo :)");
else
Console.WriteLine(" - has no stereo :)");
}
catch (Exception ex)
{
Console.WriteLine(" the 'hasStereo' of this car was not a
bool...");
Console.WriteLine(" {0}", ex.Message);
}
}

-----------------

Per

A little more about this forum entry:
http://www.pererikstrandberg.se/blog/index.cgi?page=CsharpInheritanceAndFields
Home: http://www.pererikstrandberg.se/blog/ .
Optimization in .NET: http://tomopt.com/tomnet/ .



per9000 said:
I have a question I am unable solve.
I have an inheritance graph like this:
// CAR ----- MUSICAR ---- NICECAR
// \ \
// \ +------ OLDCAR
// \
// +---- HOMEMADECAR
All originate from Car. In musiCar I introduce "public bool hasStereo"
that I can assess with a cast and the test
bool mightHaveStereo = myCar.GetType().IsSubclassOf(typeof(musiCar));
(is this the best way test that BTW?)

No, you just need:

bool mightHaveStereo = (myCar is musiCar);
Now I "want" another class that does not derive from musiCar but that
has an identical member hasStereo. I reach it and I can print it on
the console.

It would be better to have an interface which both classes implemented,
so you didn't need to use reflection...
I see that it is a bool and that it has the "correct"
name by using the following snippet:
Type T = myCar.GetType();
MemberInfo[] MIF = T.GetMembers();
foreach (MemberInfo m in MIF)
{
if (m.Name == "hasStereo" && T != typeof(niceCar))
{
Console.WriteLine(" - '{0}' : '{1}' ", m.Name, m);
}
}
}

Why don't you just use Type.GetMethod() or Type.GetProperty()?
Is there any way to get the value of myCar? I was hoping on something
like this:
((T) myCar).m;
or
if (m.isBool) myBool = ((bool)m);

It depends what kind of member it is - if it's a method, use
MethodInfo.Invoke. If it's a property, use PropertyInfo.GetValue.

As I say, it would be better not to use reflection in the first
place...
 
J

Jon Skeet [C# MVP]

per9000 said:
you pushed me in the right direction.

The testing for a stereo now looks like this:

// what if it is some other class that also might have a stereo
if (!(myCar is musiCar))
{
try
{
Type T = myCar.GetType();
FieldInfo field = T.GetField("hasStereo");

if ((bool)field.GetValue(myCar))
Console.WriteLine(" - has a stereo :)");
else
Console.WriteLine(" - has no stereo :)");
}
catch (Exception ex)
{
Console.WriteLine(" the 'hasStereo' of this car was not a
bool...");
Console.WriteLine(" {0}", ex.Message);
}
}

That means you're relying on a public hasStereo field. You shouldn't
have a public field to start with, IMO. An interface would be *so* much
nicer. Your test would be (horrible naming aside):

IPossiblyMusicalVehicle car = myCar as IPossiblyMusicalVehicle;
if (car != null)
{
if (car.HasStereo)
{
Console.WriteLine ("The car has a stereo");
}
else
{
Console.WriteLine ("The car doesn't have a stereo");
}
}

(Note also that you're using exceptions to catch things you could
easily test for - and reporting one particular error which could well
not be the cause of the exception.)
 
P

per9000

*wearing silly hat, standing in a corner, chanting "I will always
think before I implement my inheritance graph"*

Indeed, I would never do such tests in a real world scenario, I love
OO-programming and my above example is an example of failed oo-
programming. But still: it is nice to know "how you can do it", not
just knowing "how you should do it".

BTW: IPossiblyMusicalVehicle isn't that bad - I like
LongAndStrangeClassNamingUsage. (Short names quickly become hard to
understand, f.x: II = Interface(To)Ipod or if you integrate an Ipod
with an Iguana: IIII (Interface(To)IpodIntegratedIguana))

class BobsIguana : IIII
{
// ...
}

/P
--

Per Erik Strandberg

Home: http://www.pererikstrandberg.se/blog/ .
Optimization in .NET: http://tomopt.com/tomnet/ .
 
Top