2016-02-02 4 views
3

Я работаю над запутывания сборки и после запутывания PEVerify выдает следующее сообщение об ошибке:Предупреждает ли PEVerify о дублирующих методах здесь?

[MD]: Error: Method has a duplicate, token=0x060035d8. [token:0x060035D5] 
[MD]: Error: Method has a duplicate, token=0x060035d5. [token:0x060035D8] 

Вот первый метод декларации с заголовком:

// Token: 0x060035D5 RID: 13781 RVA: 0x000D7828 File Offset: 0x000D5A28 
.method private final hidebysig newslot virtual 
    instance void b() cil managed 
{ 
    .override method instance void [mscorlib]System.IDisposable::Dispose() 
    // Header Size: 12 bytes 
    // Code Size: 52 (0x34) bytes 
    // LocalVarSig Token: 0x11000050 RID: 80 
    .maxstack 2 
    .locals init (
     [0] int32 
    ) 

А вот второй один:

// Token: 0x060035D8 RID: 13784 RVA: 0x000248BC File Offset: 0x00022ABC 
.method private hidebysig 
    instance void b() cil managed 
{ 
    // Header Size: 1 byte 
    // Code Size: 31 (0x1F) bytes 
    .maxstack 8 

Похоже на явную реализацию интерфейса IDisposable для меня. Оба метода также называются, поэтому не все вызовы на один были заменены вызовами на другой. Они просто имеют одно и то же имя

Если аналогичный код был написан на C# - компилятор испустил бы методы System.IDisposable.Dispose() и Dispose(), таким образом исключив одинаковые имена и сделав PEVerify тихим.

Для того, чтобы одни и те же имена делают правильный IL, когда один из них явно переопределение метода интерфейса и другой не я написал такие образцы приложение:

namespace ClassLibrary1 { 
    public interface IX { void M(); } 
    public class Class1 : IX { 
     void IX.M() { Console.WriteLine("IX.M()"); } 
     public void M() { Console.WriteLine("M()"); } 
    } 
    public class Class2 { 
     public static void Main(string[] args) { 
      var x = new Class1(); 
      x.M(); 
      ((IX)x).M(); 
     } 
    } 
} 

IL выглядит следующим образом:

// Token: 0x06000002 RID: 2 RVA: 0x00002050 File Offset: 0x00000250 
.method private final hidebysig newslot virtual 
    instance void ClassLibrary1.IX.M() cil managed 
{ 
    .override method instance void ClassLibrary1.IX::M() 
    // Header Size: 1 byte 
    // Code Size: 13 (0xD) bytes 
    .maxstack 8 

    /* 0x00000251 00   */ IL_0000: nop 
    /* 0x00000252 7201000070 */ IL_0001: ldstr  "IX.M()" 
    /* 0x00000257 280F00000A */ IL_0006: call  void [mscorlib]System.Console::WriteLine(string) 
    /* 0x0000025C 00   */ IL_000B: nop 
    /* 0x0000025D 2A   */ IL_000C: ret 
} // end of method Class1::ClassLibrary1.IX.M 

// Token: 0x06000003 RID: 3 RVA: 0x0000205E File Offset: 0x0000025E 
.method public hidebysig 
    instance void M() cil managed 
{ 
    // Header Size: 1 byte 
    // Code Size: 13 (0xD) bytes 
    .maxstack 8 

    /* 0x0000025F 00   */ IL_0000: nop 
    /* 0x00000260 720F000070 */ IL_0001: ldstr  "M()" 
    /* 0x00000265 280F00000A */ IL_0006: call  void [mscorlib]System.Console::WriteLine(string) 
    /* 0x0000026A 00   */ IL_000B: nop 
    /* 0x0000026B 2A   */ IL_000C: ret 
} // end of method Class1::M 

Обратите внимание на разные имена методов.

Тогда я взял в результате ехе и редактируются ClassLibrary1.IX.M быть просто M в Class1 (я использовал dnSpy, чтобы сделать это). PEVerify действительно начал выпуск одной и той же проблемы с дублирующими методами, но exe все еще работает с точной печатью M() IX.M(), как и ожидалось.

Вопрос в том, является ли PEVerify чрезмерным здесь или существует проблема с совпадающими именами, которых я не вижу?

+0

«Оба метода также называются так, поэтому не все вызовы на один были заменены вызовами другого. »- когда вы вызываете не-dispose-overriding, как он узнает, что вы не пытаетесь вызвать отмену распоряжения? Да, вы можете называть его с помощью idisposable, но вы также можете его явно называть (из MSIL. Вы не можете сделать это на C#. Однако вы можете сделать это в VB). – Random832

+0

@ Random832, если я посмотрю на отредактированную сборку ildasm'а - она ​​показывает методы своими жетонами MD, и я предполагаю, что это так, как она сохраняется на в любом случае, сайты вызовов. –

+0

Это в комментариях. Исходный код имеет имя. Проблема заключается в том, что он не может знать, что компилятор действительно выбрал правильный токрен MD, потому что есть два, которые могли быть названы идентичным кодом , – Random832

ответ

4

Оба метода имеют одну и ту же подпись метода, и это просто запрещено.

For the CLR, a method signature consists of the method name, generic arity, formal parameter arity, formal parameter types and kinds, and return type.

Definition of a method signature

Serge Лидин состояния в .Net IL Assembler, глава 10 под Метод Таблица Срок действия правил:

No duplicate records—attributed to the same TypeDef and having the same name and signature—should exist unless the accessibility flag is privatescope.

, конечно, вы можете найти это правило в ECMA -335, в перегородке II.22.1:

Unique Rows: No table shall contain duplicate rows, where “duplicate” is defined in terms of its key column, or combination of columns.

+0

Спасибо за ссылку на книгу. Очень полезно. –