Retrieve value from a generic type in C#

时间:2018-06-25 19:43:37

标签: c# generics reflection

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?

2 个答案:

答案 0 :(得分:1)

失败的原因是info是一个PropertyInfo,代表一个名为Segment的属性,属于类型Entity。 (假设Entity具有这样的属性。如果没有,info为空。)

要检索该属性的值,您需要一个Entity的实例,如下所示:

var value = info.GetValue(instanceOfEntity).ToString();

相反,您尝试从Segment中读取Entity的{​​{1}}属性。

Type

您正试图从另一个属性(var value = info.GetValue(type).ToString(); 的实例中读取一个类(Segment)的属性。即使Type具有名为{{1}的属性},这是行不通的,因为TypeSegment的属性,只能从info的实例读取。

在您的方法中,没有Entity的实例。这就提出了一个问题,您想从中读取财产吗?如果该方法看起来像这样:

Entity

然后,假设该属性存在,则反射可能会起作用。但是,如果该属性存在,则只需执行以下操作:

Entity

但这是重点。之所以会出现异常,是因为您试图从另一个类的实例的一个类中读取属性。

答案 1 :(得分:0)

正如每个人都告诉您的,例外是由于段是西红柿实例的属性,而不是类型本身的属性。正如您已经发现的那样,创建实例使您可以毫无例外地访问它。您可以通过两种方法来获得期望的结果,但是在不了解上下文的情况下无法分辨出哪个更好。这里真正的问题是属性是否必须是静态的。

如果它可以是静态的,只需从public virtual string Segment { get; set; }中删除Entity并将public override string Segment => "/patch/seeded";修改为public static string Segment => "/patch/seeded";。这样,您的代码即可工作。

缺点是事实是,您必须放宽对每个从Entity派生的类的约束,必须执行一个属性Segment(顺便说一句,我将其标记为abstract而不是virtual),这意味着您应该检查{{1 }},然后在您的方法中使用它。

如果您想/需要保持您的Segment虚拟/抽象,除了创建T的实例,别无其他方法。可以像示例代码中那样通过反射来完成,但是最好添加一个new( )以这种方式约束T:

info != null