Reputation: 2073
I want to get the value of a generic type, passed through to a method, which looks like this:
public virtual Domains.Vegetable.Result Get<T>() where T: Domains.Vegetable.Entity
{
var type = typeof(T);
var info = type.GetProperty("Segment");
var value = info.GetValue(type).ToString(); // throws exception
// NOTE: I have tried this, which works, but this feels wrong
//var entity = Activator.CreateInstance<T>();
//var segment = entity.Segment;
// omitted for brevity
}
The entity called Domains.Vegetable.Entity looks something like this:
public abstract class Entity
{
/// <summary>
///
/// </summary>
public virtual string Segment { get; set; }
}
which is then implemented on any object of my choosing:
public class Tomato: Vegetable.Entity
{
/// <summary>
///
/// </summary>
public override string Segment => "/patch/seeded";
}
So, if I call my method: Get<Tomato>()
, I'm expecting to get the value "/patch/seeded" back in the method mentioned above.
Is this even possible?
Upvotes: 0
Views: 2345
Reputation: 7468
As everybody told you the exception is due to the fact that Segment is a property of the instances of tomato, and not of the type itself. And as you already found out creating an instance let you access it without exceptions. There are 2 ways you can follow to achieve the result you are expecting, but it's impossible to tell which is the better without knowing the context. The real question here is whether the property has to be static or not.
If it can be static just remove public virtual string Segment { get; set; }
from Entity
and modify public override string Segment => "/patch/seeded";
into public static string Segment => "/patch/seeded";
. In this way your code will work.
The drawback is the fact that you loose the constraint of every class derived from Entity having to implement a property Segment (btw I would have it marked as abstract instead of virtual), and this means that you should check for info != null
before using it in your method.
If you want/need to keep your Segment virtual/abstract there is no other way than creating an instance of T. This can be done via reflection as in your sample code, but maybe it'd be better adding a new() constraint on T in this way:
public virtual Domains.Vegetable.Result Get<T>() where T: Domains.Vegetable.Entity, new()
{
var entity = new T();
var segment = entity.Segment;
// omitted for brevity
}
Upvotes: 0
Reputation: 29207
The reason this fails is that info
is a PropertyInfo
representing a property named Segment
belonging to type Entity
. (Assuming that Entity
has such a property. If it doesn't, info
is null.)
In order to retrieve the value of that property you need an instance of Entity
, like this:
var value = info.GetValue(instanceOfEntity).ToString();
Instead, you're trying to read the Segment
property an Entity
from a Type
.
var value = info.GetValue(type).ToString();
You're trying to read the property of one class (Segment
) from an instance of another property (Type
.) Even if Type
had a property named Segment
it wouldn't work, because info
is a property of Entity
and can only be read from an instance of Entity
.
In your method there's no instance of an Entity
. That raises the question, what are you trying to read the property from? If the method looked like this:
public virtual Domains.Vegetable.Result Get<T>(T entity) where T: Domains.Vegetable.Entity
{
var type = typeof(T);
var info = type.GetProperty("Segment");
var value = info.GetValue(entity).ToString(); // throws exception
// other stuff
}
then the reflection might work, assuming that the property exists. But if the property existed you would just do this:
public virtual Domains.Vegetable.Result Get<T>(T entity) where T: Domains.Vegetable.Entity
{
var value = entity.Segment.ToString(); // throws exception
// other stuff
}
But that's beside the point. You're getting an exception because you're trying to read a property from one class on an instance of a different class.
Upvotes: 1