Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properties inheritance issue #1949

Open
greenozon opened this issue Mar 8, 2020 · 6 comments
Open

Properties inheritance issue #1949

greenozon opened this issue Mar 8, 2020 · 6 comments
Labels
Bug C# Decompiler The decompiler engine itself Help Wanted

Comments

@greenozon
Copy link

ILSpy version 6.0.0.5613-preview2

Seen this kind of issue:

  1. there are some Properties in parent interface, eg:
    image

  2. there is a class that implements it (inherits)
    image

as you see it decompiles in low level format, not as high level C# is expecting..

target:

err93.zip

@greenozon
Copy link
Author

Similar issues might be found in

public abstract class WcfLogReceiverClientBase : ClientBase, IWcfLogReceiverClient, ICommunicationObject where TService : class

@siegfriedpammer
Copy link
Member

Simple example:

  1. Library project
using System;

namespace Library
{
    public class TestBase : IDisposable
    {
        public void Dispose() { }
        public int Port { get; set; }
        public void Send(string msg) { }
    }
}
  1. Test project
using Library;
using System;

namespace Issue1949
{
    interface ITest : IDisposable
    {
        int Port { get; set; }
        void Send(string msg);
    }

    class Test : TestBase, ITest
    {
    }
}

produces this exact code pattern:

// Issue1949.Test
using Issue1949;
using Library;
using System;

internal class Test : TestBase, ITest, IDisposable
{
	int ITest.get_Port()
	{
		return base.Port;
	}

	void ITest.set_Port(int value)
	{
		base.Port = value;
	}

	void ITest.Send(string msg)
	{
		Send(msg);
	}
}

@siegfriedpammer
Copy link
Member

Notes:

  • The metadata does not contain an entry for int Port { get; set; } for ITest on the Test class. That's why we're displaying it as two separate methods.
  • Seems these proxy calls are emitted under the following conditions:
  1. Type ThisAssembly.A inherits from OtherAssembly.BaseA which defines a non-virtual property P.
  2. Type ThisAssembly.A implements interface I1 which defines a property P with the same signature as OtherAssembly.BaseA.P.

For the interface to be correctly implemented the methods must support callvirt. The compiler emits virtual proxy methods that forward the call to the base class.

@siegfriedpammer siegfriedpammer added Bug C# Decompiler The decompiler engine itself labels Mar 9, 2020
@siegfriedpammer
Copy link
Member

See also #1682

@siegfriedpammer
Copy link
Member

A fix for this could easily implemented once we have a proper API that allows us to categorize/analyze the "role" of a method/type. See #1926

@dgrunwald
Copy link
Member

I think the solution here is to detect where an explicit interface implementation looks like it might have been generated by the C# compiler:
https://github.com/dotnet/roslyn/blob/fb028b7c198c2f726067bb8627cb014f1154a541/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs#L1466-L1523

If an explicit interface implementation would be re-generated by the compiler on re-compilation, we should omit it during decompilation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug C# Decompiler The decompiler engine itself Help Wanted
Projects
None yet
Development

No branches or pull requests

3 participants