Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emit of explicit method override hides property

There is a class with one property:

public class BaseClass
{
  public virtual string Property1 { get; set; }
}

Now I create a derived type with some method overrides:

[Test]
public void name ()
{
  var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("Test"), AssemblyBuilderAccess.RunAndSave);
  var moduleBuilder = assemblyBuilder.DefineDynamicModule ("Test.dll");
  var derivedBuilder = moduleBuilder.DefineType ("DerivedClass", TypeAttributes.Public, typeof (BaseClass));

  const MethodAttributes methodAttributes = MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.NewSlot;

  var getterOverride = derivedBuilder.DefineMethod (
      "get_Property1",
      methodAttributes,
      typeof (string),
      Type.EmptyTypes);
  var getterILGenerator = getterOverride.GetILGenerator();
  getterILGenerator.Emit (OpCodes.Ldnull);
  getterILGenerator.Emit (OpCodes.Ret);
  derivedBuilder.DefineMethodOverride (getterOverride, typeof (BaseClass).GetMethod ("get_Property1"));

  var setterOverride = derivedBuilder.DefineMethod (
      "set_Property1",
      methodAttributes,
      typeof (void),
      new[] { typeof (string) });
  var setterILGenerator = setterOverride.GetILGenerator ();
  setterILGenerator.Emit (OpCodes.Ret);
  derivedBuilder.DefineMethodOverride (setterOverride, typeof (BaseClass).GetMethod ("set_Property1"));

  var derivedType = derivedBuilder.CreateType();
  var props = derivedType.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

  assemblyBuilder.Save ("Test.dll");

  Assert.That (props, Has.Length.EqualTo (1));
}

The generated type doesn't contain the property anymore. Curiously the property appears again if you change the methodAttributes to MethodAttributes.Public for at least one method definition.

Seems like a bug?

Edit: peverify doesn't give an error.

Edit: (important comment of Fabian Schmied)

ECMA-335 Partition II, 10.3.3: "If a type overrides an inherited method via a MethodImpl, it can widen or narrow the accessibility of that method."

like image 872
Matthias Avatar asked Oct 07 '22 00:10

Matthias


1 Answers

Since the specs (ECMA-335, II.10.3.3) explicitly allow one to narrow the visibility of methods overridden via a MethodImpl ("explicit overrides", expressed by Reflection.Emit via TypeBuilder.DefineMethodOverride), I believe this is indeed a bug in the Reflection implementation and should be reported via Microsoft Connect.

like image 126
Fabian Schmied Avatar answered Oct 13 '22 12:10

Fabian Schmied