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

VB -> C#: Explicit interface implementation adds a setter for readonly property. #813

Closed
Yozer opened this issue Jan 12, 2022 · 3 comments · Fixed by #822
Closed

VB -> C#: Explicit interface implementation adds a setter for readonly property. #813

Yozer opened this issue Jan 12, 2022 · 3 comments · Fixed by #822
Labels
help wanted VB -> C# Specific to VB -> C# conversion

Comments

@Yozer
Copy link
Member

Yozer commented Jan 12, 2022

VB.Net input code

Public Interface IUser
    ReadOnly Property Username As String
End Interface

Public Class User
    Implements IUser

    Public Property Nick As String Implements IUser.Username
        Get
            Throw New NotImplementedException
        End Get
        Set
            Throw New NotImplementedException
        End Set
    End Property

End Class

Erroneous output

    public interface IUser
    {
        string Username { get; }
    }

    public class User : IUser
    {
        string IUser.Username
        {
            get
            {
                throw new NotImplementedException();
            }

            set
            {
                throw new NotImplementedException();
            }
        }

        public string Nick { get => ((IUser)this).Username; set => ((IUser)this).Username = value; }
    }

    static class Module1
    {
        public static void Main()
        {
            var test1 = "" ?? () => 5;
            var test2 = () => 4 ?? () => 5;
        }
    }

Expected output

    public interface IUser
    {
        string Username { get; }
    }

    public class User : IUser
    {
        public string Nick
        {
            get
            {
                throw new NotImplementedException();
            }

            set
            {
                throw new NotImplementedException();
            }
        }

        string IUser.Username => Nick;
    }

Details

  • Product in use: VS extension
  • Version in use: 8.4.4.0
  • Did you see it working in a previous version, which?
  • Any other relevant information to the issue, or your interest in contributing a fix.

Could the fix be to always keep the getter/setter in a class property and just generate delegate calls from all explicit interface implementations?

@Yozer Yozer added the VB -> C# Specific to VB -> C# conversion label Jan 12, 2022
@GrahamTheCoder
Copy link
Member

Your suggestion might well work. To figure it out, it might be best to check the decompilation in SharpLab.
It needs to still do the right thing when someone overrides the method, and when someone uses an _ to directly write to the underlying field (if that's possible in this case)

See the slightly related #685

@GrahamTheCoder
Copy link
Member

From a quick look:

  • SharpLap doesn't accurately decompile the code
    • I believe this is a bug in ILSpy which it's using, because the IL can't be directly represented in C#, arguably it's doing the best it can, but a warning of non-translatable IL might have been nice
  • It looks like the underscore syntax doesn't work for this case (presumably since it's not an auto-implemented property within the class - phew)

The way I'd expect overriding Username to work is that Nick's behaviour wouldn't change. So actually it sounds like flipping it around like you suggest would be an improvement there. That said, it's definitely worth a test.

There are some self verifying test cases in the converter which we could add an example to (they are executed in VB, then converted and executed again):
https://github.com/icsharpcode/CodeConverter/blob/master/Tests/TestData/SelfVerifyingTests/VBToCS/InheritanceTests.vb

@Yozer
Copy link
Member Author

Yozer commented Jan 28, 2022

I'm slowly starting to look into this, first, there is a small code cleanup around the visitors in #821
What I found is that the current way of generating explicit implementations can change the application logic.
You can find a self-verifying test (currently failing) for it in #822

If this property
Protected Overridable Property Nick As String Implements IUser.Username
is overridden in a deriving class then it also changes the behavior of IUser.Username.

After conversion:

string IUser.Username { get { logic }  set { logic } }
protected virtual string Nick { get => ((IUser)this).Username; set => ((IUser)this).Username = value; }

Because the converter keeps the logic in the first explicit interface implementation it means that logic IUser.Username will never change and this isn't how vb.net works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted VB -> C# Specific to VB -> C# conversion
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants