【问题标题】:Reflection: Property-GetValue by Class-Type (so without an instantiated Object)反射:按类类型的 Property-GetValue(因此没有实例化对象)
【发布时间】:2015-11-27 18:28:38
【问题描述】:

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

今天我遇到了两个投影具有相同ProjectionTypeName 的问题,这造成了很多麻烦。所以我决定做一个单元测试来防止这种情况再次发生。

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

// 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."。

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

如果我有一个实例化的对象,我将能够做这样的事情:

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

【问题讨论】:

    标签: c# reflection types properties typeof


    【解决方案1】:

    改用自定义属性怎么样?

    [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
    }    
    

    【讨论】:

    • 嗯,这看起来很有希望,而且更干净。我目前很忙,所以我没有时间尝试其他需要我注意的更高优先级的问题,因为上面的 UnitTest 解决了我的问题。不过,+1,当我有更多时间时,我会将它放在我的 TODO 列表中。
    【解决方案2】:

    好的,根据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:

    请不要这样做。 曾经。太可怕了。应该被践踏 上,切成小块,点燃,然后再切。乐趣 不过,不是吗? ;)

    【讨论】:

    • 为什么不使用 Jons 答案底部的简单委托解决方案?
    • @usr 因为我不能做他第二个代码的这部分:Func&lt;MyClass,因为我不能使用MyClass,所以我只有MyClass的Type。
    • 使用 MakeGenericType 创建委托类型并使用 DynamicInvoke 调用它。为您节省了晦涩难懂的 IL 代。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    相关资源
    最近更新 更多