Get object sub-property based on condition
I am trying to do something like the following...
if (source.Type == 'cat')
return source.cat.feedDate == null
? ""
: source.cat.feedDate.Value;
else
return source.dog == null
? ""
: source.dog.feedDate== null
开发者_JAVA百科 ? ""
: source.dog.feedDate.Value;
cat and dog could be anything but will always have the feedDate property, but they implement different interfaces which I have no control of.
Is there a better way to write this code, to be more reusable? there may well be more properties too, such as source.cat.napTime and source.dog.napTime. So I am looking for a generic method that can pluck out the value based on a supplied property name and a 'source' object.
If there's only one place you need to do this, then Reflection and/or dynamic would work well.
But if you find yourself doing this throughout your code, you might want to consider writing your own adapters around the classes you can't control. Then you could use polymorphism (you could define a base AnimalAdapter, with CatAdapter and DogAdapter descendants, and then write code that uses AnimalAdapter and calls virtual methods on it).
public abstract class AnimalAdapter {
public abstract DateTime? FeedDate { get; }
public abstract DateTime? NapTime { get; }
}
public class CatAdapter : AnimalAdapter {
private Cat _cat;
public CatAdapter(Cat cat) { _cat = cat; }
public override DateTime? FeedDate { get { return _cat.feedDate; } }
public override DateTime? NapTime { get { return _cat.napTime; } }
}
public class DogAdapter : AnimalAdapter {
private Dog _dog;
public DogAdapter(Dog dog) { _dog = dog; }
public override DateTime? FeedDate { get { return _dog.feedDate; } }
public override DateTime? NapTime { get { return _dog.napTime; } }
}
If, when the Cat or Dog object is initially created, you know which it is (e.g., if you have one code path that instantiates a Cat, and another that instantiates a Dog), then you can just create your wrapper right then. But if you're given a "source" object, as in your example, that just gives you a base class (or just an object
), then you'll also want to add a factory method, which would probably go on AnimalAdapter:
public static AnimalAdapter FromAnimal(object animal) {
var cat = animal as Cat;
if (cat != null)
return new CatAdapter(cat);
var dog = animal as Dog;
if (dog != null)
return new DogAdapter(dog);
throw new ArgumentException("Unexpected animal type");
}
maybe something like:
// get .dog. etc
var prop = source.GetType().GetProperty(source.Type);
dynamic subObj = prop == null ? null : prop.GetValue(source,null);
return (subObj == null || subObj.feedDate == null) ? ""
: subObj.feedDate.Value.ToString();
Or if the member-name (feedTime) is dynamic too:
static object Get(dynamic source, string memberName)
{
var prop = source.GetType().GetProperty(source.Type);
object subObj = prop == null ? null : prop.GetValue(source, null);
var subProp = subObj == null ? null : subObj.GetType().GetProperty(memberName);
return subProp == null ? null : subProp.GetValue(subObj, null);
}
if (source.GetType() == typeof(cat))
return source.cat.feedDate ?? string.Empty;
if (source.GetType() == typeof(dog))
return source.dog.feedDate ?? string.Empty;
精彩评论