反射:Class-Type的Property-GetValue(所以没有实例化的Object)

时间:2015-09-02 09:49:17

标签: c# reflection types properties typeof

在我们的项目中,我们有多个所谓的Projections。这些Projection - 类都有一个带有get的字符串属性,称为ProjectionTypeName。对于所有预测,此ProjectionTypeName应该是唯一的。

今天我遇到了两个预测具有相同ProjectionTypeName的问题,这导致了很多麻烦。所以我决定制作一个UnitTest来防止再次发生这种情况。

我使用以下方法获取所有Types的所有Projections

// The excluded abstract projections
private static readonly List<Type> AbstractProjections = new List<Type>
{
    typeof(AbstractRavenDbChangesProjection),
    typeof(AbstractRavenDbTimelineProjection)
};

private static IEnumerable<Type> GetAllProjectionTypes()
{
    return typeof(AbstractRavenDbChangesProjection)
        .Assembly
        .GetTypes()
        .Where(x => typeof(AbstractRavenDbChangesProjection).IsAssignableFrom(x) && !x.IsInterface)
        .Except(AbstractProjections)
        .ToList();
}

然后我做了实际测试:

[Test]
public void TestNoDuplicated()
{
    var noDuplicatedList = new Dictionary<Type, string>();
    var projectionTypes = GetAllProjectionTypes();
    foreach (var type in projectionTypes)
    {
        // TODO: Get projectionTypeName-value by Projection's Type
        var projectionTypeName = ??;

        Assert.IsFalse(noDuplicatedList.ContainsValue(projectionTypeName),
            "{0} has been found as ProjectionTypeName in two different Projections: {1} & {2}",
                projectionTypeName,
                noDuplicatedList.First(x => x.Value == projectionTypeName).Key,
                type);
            noDuplicatedList.Add(type, projectionTypeName);
    }   
}

我已经看了一下甚至试过a piece of code by @JohnSkeet,即使他说(并且我引用):

  

请不要这样做。永远。它很可怕。它应该被践踏,   切成小块,着火,然后再次切断。虽然好玩,   不是吗? ;)

但是看起来自2012年(发布答案时)已经改变了,当你尝试这种反思时,.NET现在会出错:"System.Security.VerificationException : Operation could destabilize the runtime."

所以,我的问题。当我只能处理类的ProjectionTypeName时(而不是实际的实例化对象),如何获取字符串属性Type的值。

如果我有一个实例化的对象,我可以做这样的事情:

myInstantiatedObject.GetType().GetProperty("ProjectionTypeName")
    .GetValue(myInstantiatedObject, null);

2 个答案:

答案 0 :(得分:2)

如何使用自定义属性呢?

[AttributeUsage(System.AttributeTargets.Class)]
public sealed class ProjectionTypeNameAttribute : Attribute
{
  private string m_Name;

  public string Name
  {
    get { return m_Name; }
  }

  public ProjectionTypeNameAttribute(string name)
  {
    m_Name = name;
  }
}

[ProjectionTypeNameAttribute(ProjectionWhatever.PROJECTION_NAME)]
public class ProjectionWhatever
{
  public const string PROJECTION_NAME = "Whatever";

  // if you want to have property as well
  public string ProjectionTypeName
  {
    get
    {
      return PROJECTION_NAME;
    }
  }
}   

// query if type has attribute
var type = typeof(ProjectionWhatever);
var attributes = type.GetCustomAttributes(typeof(ProjectionTypeNameAttribute), false);
if (attributes != null && attributes.Length > 0)
{
  var attribute = (ProjectionTypeNameAttribute)attributes[0];
  // use attribute.Name
}    

答案 1 :(得分:1)

好的,基于this answer,我找到了让John Skeet代码正常工作的答案。

我的问题是这一行:

var dynamicMethod = new DynamicMethod("TempUglyPropertyGetMethod", typeof(string),
    Type.EmptyTypes, Assembly.GetExecutingAssembly().ManifestModule);

缺少Assembly.GetExecutingAssembly().ManifestModule作为附加参数。这是我的工作测试代码:

// https://stackoverflow.com/questions/11162652/c-sharp-get-property-value-without-creating-instance/11162876#11162876
var method = type.GetProperty("ProjectionTypeName").GetGetMethod();
var dynamicMethod = new DynamicMethod("TempUglyPropertyGetMethod", typeof(string),
    Type.EmptyTypes, Assembly.GetExecutingAssembly().ManifestModule);
var generator = dynamicMethod.GetILGenerator();
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Call, method);
generator.Emit(OpCodes.Ret);
var tempUglyPropertyGetMethod = (Func<string>)dynamicMethod.CreateDelegate(typeof(Func<string>));
var projectionTypeName = tempUglyPropertyGetMethod();

再一次,不要在实际项目中使用它。我只用它来测试这个测试用例。再次引用@JohnSkeet:

  

请不要这样做。 永远。它可怕。它应该被践踏   在,切成小块,着火,然后再次切断。开玩笑   虽然,不是吗? ;)