roslyn: EditorBrowsable(EditorBrowsableState.Never) in VS 2015 does not work as well as it does in VS 2013
Problem
Consider the following projects and classes:
ProjectA
is not included in the solution
namespace ProjectA
{
using System;
using System.ComponentModel;
public class BaseClass
{
[EditorBrowsable(EditorBrowsableState.Never)]
public new Type GetType() { return base.GetType(); }
[EditorBrowsable(EditorBrowsableState.Never)]
public new static bool Equals(object objA, object objB) { return Object.Equals(objA, objB); }
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) { return base.Equals(obj); }
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() { return base.GetHashCode(); }
[EditorBrowsable(EditorBrowsableState.Never)]
protected new object MemberwiseClone() { return base.MemberwiseClone(); }
[EditorBrowsable(EditorBrowsableState.Never)]
public new static bool ReferenceEquals(object objA, object objB) { return Object.ReferenceEquals(objA, objB); }
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() { return base.ToString(); }
public static void DoSomeBasicThing() {}
}
}
namespace ProjectA
{
public class ClassA : BaseClass
{
public static void InitializeClassA() { }
public void DoSomethingA() {}
}
}
ProjectB
is included in the solution; has a binary reference to ProjectA
namespace ProjectB
{
using System.ComponentModel;
using ProjectA;
[EditorBrowsable(EditorBrowsableState.Never)]
public class ClassB : BaseClass, IInterfaceA<ClassB>
{
public void DoSomethingB()
{
var objectA = new ClassA();
}
}
}
ProjectC
is included in the solution; has a binary reference to ProjectA; has a project reference to ProjectB
namespace ProjectC
{
using ProjectB;
public class ClassC
{
public void TestEm()
{
var objectB = new ClassB();
}
}
}
In Visual Studio 2013 the EditorBrowsable
attribute is honored correctly for members of types defined in assemblies that are included using a binary reference. However, in Visual Studio 2015, some of the methods defined on the System.Object
[static Equals, static ReferenceEquals, and GetType] appear in the Intellisense menu despite being marked with the EditorBrowsable
attribute with the EditorBrowsableState.Never
argument in a sub class via new
hiding methods.
Here are some screenshots:
Visual Studio 2013 - viewing ProjectA.ClassA’s Intellisense menu from ProjectB.ClassB: | Visual Studio 2015 - viewing ProjectA.ClassA’s Intellisense menu from ProjectB.ClassB: |
---|---|
![]() |
![]() |
Visual Studio 2013 - viewing objectA’s Intellisense menu from ProjectB.ClassB: | Visual Studio 2015 - viewing objectA’s Intellisense menu from ProjectB.ClassB: |
---|---|
![]() |
![]() |
Visual Studio 2013 - viewing ProjectB.ClassB’s Intellisense menu from ProjectC.ClassC: | Visual Studio 2015 - viewing ProjectB.ClassB’s Intellisense menu from ProjectC.ClassC: |
---|---|
![]() |
![]() |
Visual Studio 2013 - viewing objectB’s Intellisense menu from ProjectC.ClassC: | Visual Studio 2015 - viewing objectB’s Intellisense menu from ProjectC.ClassC: |
---|---|
![]() |
![]() |
Note that this is the additional problem I mentioned in #4358 in the footnote of this comment.
About this issue
- Original URL
- State: open
- Created 9 years ago
- Reactions: 16
- Comments: 44 (25 by maintainers)
Commits related to this issue
- Update EditorBrowsableAttribute.xml It said does not suppress members from a class in the same ``assembly``. This must be ``solution``. This changed from VS2013 to VS2015. See https://github.com/dot... — committed to sonnemaf/dotnet-api-docs by sonnemaf 3 years ago
- Move common package references to central file Remove also rather useless IFluentInterface since it's not really working as pre-VS2013 (see https://github.com/dotnet/roslyn/issues/4434) — committed to devlooped/Merq by kzu 2 years ago
I don’t understand why this is so hard to fix? It should be a piece of cake now that Intellisense already got filtering by types, methods, properties, etc.
Is this a VS thing, or Roslyn? Which system is responsible for Intellisense population?
So that’s up with this? It was added to the 2.0 milestone but appears to still be an issue. Is there any work for a fix going on regarding this bug?
As far as intended behavior, I’d say the members with
EditorBrowsableState.Never
should never be show, regardless of how the member was discovered (current project, project reference or assembly reference). An improvement would be to show it anyway for the first two, but I’d say it’s very much a nice too have with very low pri.And the VB side would be derived from this:
https://github.com/dotnet/roslyn/blob/089be987071b4d088dda1f5a1e35a9cf8d03d2b5/src/Compilers/VisualBasic/Portable/Symbols/Source/OverrideHidingHelper.vb#L278-L314
Fixing this just requires this code:
https://github.com/dotnet/roslyn/blob/089be987071b4d088dda1f5a1e35a9cf8d03d2b5/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs#L664-L676
to use this code instead:
https://github.com/dotnet/roslyn/blob/089be987071b4d088dda1f5a1e35a9cf8d03d2b5/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs#L4121-L4149
We seemed to have traded one evil for another and at the same time introduced a breaking change. Making changes like this doesn’t seem like good engineering practice to me.
@Scottj1s @TyreeJackson, something like
EditorBrowsableState.Never_We_Really_Mean_It_This_Time
feels like the incorrect solution to a problem that never should’ve existed. I imagine if we went back in time before this breaking change was introduced, we wouldn’t come up with this solution.I understanding wanting to preserve the current behavior of
EditorBrowsableState.Never
for those that are now dependent on it. But I would vote for an MSBuild project property that can used to opt-in to this behavior:Then we can have a more correct solution using your suggestion of
EditorBrowsableState.InternalOnly
. This should behave identically to theinternal
keyword, meaning that assemblies who are granted internal access viaInternalsVisibleTo
would also see metadata tagged withEditorBrowsableState.InternalOnly
.No updates on this after 5 years?!
Can we have a new
EditorBrowsableState.Never_We_Really_Mean_It_This_Time
state for those of us who don’t want to see members even in their own projects? Or perhaps a more appropriate option would be to add aEditorBrowsableState.InternalOnly
for those who want to see the member in their projects but not outside of their project. It’s strange to change the meaning ofNever
after so many years of respecting it.@JieCarolHu @sharwell what is the status of this? I am interested in helping to get this issue fixed.
@JieCarolHu it looks like you have done some work on this in the past (#25290), but the PR is closed and appears dead for several months. Is there still work on this? Was it killed because of the required public API changes?
The work in #25290, although incomplete, does appear to fix some cursory unit tests I wrote up for this issue. What is the blocker on finishing this work? Presumably approval or buy-in from whomever owns the relevant public APIs?
@dpoeschl and I are interested in seeing this completed, but it doesn’t currently fix into our scheduling. I’m hoping a community user picks it up so it can ship in 15.5.
Requirements
Time requirement
This will probably take a new user up to a week or more, or an experienced user a few days.
Work would need to start within the next week to ensure time for this to ship in 15.5 (the earliest release where it would currently be possible).
Interested?
If you are interested, please let us know. If more than one person is interested, that would be acceptable for this issue. In particular, it will be good to have more than one person test the intended behavior in Visual Studio 2013, and more than one person review the test cases to ensure they accurately represent the intended behavior so we do not regress in the future.
The NUnit team is suffering from this issue when developing our
Assert
API. We’d like to hideEquals
, to prevent users from accidentally entering the following:When they should have entered:
The following appears to work fine in Visual Studio 2013:
But no longer works in Visual Studio 2015:
You can find the issue here: https://github.com/nunit/nunit/issues/1726#issuecomment-255089011
See also: https://twitter.com/jcansdale/status/788704315695398912 😉
@komdil
We would take a contribution to apply the design if a motivated party were to provide it.
@dessyordanova see https://github.com/dotnet/roslyn/issues/4434#issuecomment-675676789
This is still an issue in VS 2022 😦
@jods4 This issue tracks fixing a bug where the behavior of the attribute changed in Visual Studio 2015 relative to Visual Studio 2013. The cause of the behavior change, and the resulting behavior after the bug is fixed are both well understood. However, the behavior change requested in https://github.com/dotnet/roslyn/issues/4434#issuecomment-780692732 does not align with the behavior of the feature in any previous version of Visual Studio, making it a separate request; if it isn’t tracked as a separate issue it’s likely to be lost once this issue is fixed.
@AradAral See https://github.com/dotnet/roslyn/issues/4434#issuecomment-675676789