As i'm fooling around with Reflection
, i've come across such an exquisite behavior, when it comes to recursion. Let me introduce and further explain my code:
using System;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
public class Car
{
public Chassis Chassis { get; set; }
public Tire Tire { get; set; }
public Car(Chassis chassis)
{
Chassis = chassis;
}
}
public class Chassis
{
public string Serial { get; set; }
public string Size { get; set; }
public Chassis(string serial)
{
Serial = serial;
}
}
public class Tire
{
public string Brand { get; set; }
public string Color { get; set; }
}
public static bool AreAllPropertiesNull<T>(T obj)
{
if (obj == null) return true; //If object is null, break from everything. The car has something
if (obj is string && !string.IsNullOrEmpty(obj.ToString())) return false; //If it's a string and has something, the car has something
return typeof(T).GetProperties().All(propertyInfo => AreAllPropertiesNull(propertyInfo.GetValue(obj, null))); //Recursion. Look inside child properties for valid data
}
static void Main(string[] args)
{
var nobodysCar = new Car(null);
var mikesCar = new Car(new Chassis("XE83JB28"));
if (AreAllPropertiesNull(nobodysCar))
{
Console.WriteLine("No one's car is null. No wonder.");
}
if (AreAllPropertiesNull(mikesCar))
{
Console.WriteLine("Mike's car is null, But the chassis has data in it. That doesn't look right.");
}
var justTheChassis = new Chassis("XE83JB28");
if (AreAllPropertiesNull(justTheChassis))
{
Console.WriteLine("The chassis is null. Fortunately, this message won't ever be shown.");
}
Console.ReadLine();
}
}
}
In it, I wish to do the following:
- Instantiate a
Car
, one with no data at all and one with a child object (Chassis
), which contains some data; - Check whether or not the two objects have data in them, by means of the
AreAllPropertiesNull
method. The method will traverse inside all child objects, checking their properties; - If all properties in all child objects are empty, show a message for each.
The application outputs:
No one's car is null. No wonder.
Mike's car is null, But the chassis has data in it. That doesn't look right.
Huh? Inside the recursions of AreAllPropertiesNull
, the method was provided with an object of the type Chassis
, with a string
containing "XE83JB28". Yet it'll recognize it as empty. Why is that? While debugging, I could see that the object was of type Chassis
, and it had data in it. Now, let's provide the same method with the same data (zooming in at the last lines of the above example):
var justTheChassis = new Chassis("XE83JB28");
if (AreAllPropertiesNull(justTheChassis))
{
Console.WriteLine("The chassis is null. Fortunately, this message won't ever be shown.");
}
As you can imagine, the message won't be shown, as the Chassis
object has something in it. So, if i'm not crudely mistaken, at some point in the application, the AreAllPropertiesNull
method received exactly the same input, yet yielded different results.
I already got the solution: use obj.GetType()
instead of typeof(T)
. Then it'll all be fine and dandy. I realize that the former is the runtime type and the latter is the compile time type. But I can't wrap my head around the fact that the algorithm received a valid object and failed to recognize its data. Can someone shine a light on this issue?
TL;DR: Compile my example and check the output. Then change typeof(T)
for obj.GetType()
. The output has changed. Why?
Aucun commentaire:
Enregistrer un commentaire