C#属性是否可以没有GetMethod而没有SetMethod

时间:2016-08-17 21:26:32

标签: c# reflection linq-expressions propertyinfo

浏览System.Linq.Expressions的.NET核心源代码,我发现以下代码位于here

MethodInfo mi = property.GetGetMethod(true);
if (mi == null)
{
    mi = property.GetSetMethod(true);
    if (mi == null)
    {
        throw Error.PropertyDoesNotHaveAccessor(property, nameof(property));
    }
}

GetGetMethod GetSetMethod是否有任何方法可以返回null,这似乎可以解释为什么?这是死代码吗? C#编译器不允许属性没有getter而没有setter,所以PropertyInfo如何实现。

我的动机是通过添加测试覆盖率来为OSS代码做出贡献,所以我试图看看哪些测试用例会覆盖这个

3 个答案:

答案 0 :(得分:4)

您可以在IL中创建一个没有访问者的属性:

.class public C
{
  .property int32 Count() { } 
}

然后可以触发您提到的代码路径:

var prop = typeof(C).GetProperty("Count", BindingFlags.NonPublic | BindingFlags.Instance);

Expression.Property(null, prop);

此代码抛出:

  

ArgumentException:属性'Int32 Count'没有'get'或'set'访问者

答案 1 :(得分:2)

根据CLI Specification

  

CLS规则28:属性应遵循特定的命名模式。看到   §I.10.4。 CLS规则24中引用的SpecialName属性应为   在适当的名称比较中忽略,并应遵守标识符   规则。属性应具有getter方法,setter方法或   两者。

这是链接PDF的第52页。

这似乎说一个或那个必须在那里。

开发人员似乎决定以这种方式解释规范,并在面对无效数据时采取相应行动。看起来很合理。

通过编写IL或之后编辑元数据,可以创建一个没有getter或setter的属性。并且.NET加载器可能会继续加载它,即使它被认为是无效的属性。我见过这种事情发生在其他领域。

考虑到这一点,处理具有getter和setter的属性的“不可能”情况的代码对我来说似乎不是死代码。

答案 2 :(得分:2)

经过一些研究,有一种方法可以通过System.Reflection.Emit

实现这一目标
AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Name"), AssemblyBuilderAccess.Run);
ModuleBuilder module = assembly.DefineDynamicModule("Module");

TypeBuilder type = module.DefineType("Type");
PropertyBuilder property = type.DefineProperty("Property", PropertyAttributes.None, typeof(void), new Type[0]);

Type createdType = type.CreateType();
PropertyInfo createdProperty = createdType.GetTypeInfo().DeclaredProperties.First();

Console.WriteLine(createdProperty.GetGetMethod(true) == null);
Console.WriteLine(createdProperty.GetSetMethod(true) == null);

这显然是一种没有IL

的没有setter或getter的奇怪方法