Share via


Now where did I put that member?

Got this Ladybug report from a customer concerned that intellisense was broken because he wasn't seeing all the valid members in a drop down list when he did this:

        public void DoSomethingOfRelevance()

        {

            PrintPreviewDialog ppDialog;

            ppDialog<dot>

        }

Specifically, items in the list that were missing were properties like "WindowState", "PrintPreviewControl" and others. Oddly enough I'd just debugged an incredibly similar matter with Daigo concerning System.Windows.Forms.CheckedListBox and the DataSource property. He was incredibly frustrated and came to me to tell me that Intellisense was broken and that he should be seeing this member in the list. At first I thought it must be something wrong with our metadata reader. If we can't understand something from metadata we don't read it in and proceed to the next thing in the assembly (this is actually pretty common as many languages out there produce things we can't understand (like properties with multiple arguments (whee! nested parenthesis are fun!))). However, in this case it turns out that we were reading it in just fine. So what could be the problem? Anyone out there have an idea?

*chirp*

Well, I could wait for ideas, but I should just tell you. As it turns out the member was marked in metadata as having the following property: 

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

From the docs you can see that the attribute is used to: "Specifies that a property or method is viewable in an editor" and that the value passed in states: "The property or method is never browsable from within an editor". And, if you look at the DataSource property you'll see that it has these docs: "This member supports the .NET Framework infrastructure and is not intended to be used directly from your code." Note: there is also a state called "Advanced" and one can view items marked as advanced if they toggle

 Tools | Options | Text Editor | All Languages | Statement Completion | Hide Advanced Members.

Now, the reason we read it in from metadata is that we need to make sure that we know about that member so that it will appropriately hide members. Using Daigo's example, if we were to forget about that member then we'd place ListControl.DataSource in the list (ListControl is a base type of CheckedListBox) which would be really bad as you'd think that that was the datasource you were accessing when in actuallity your compiled code would access the datasource in the derived type.

Personally, I find this behavior incredibly confusing, frustrating and scary. As a developer one rightly gets quite confused when the docs tell you one thing and intellisense seems to tell you something else. One also wonders why in this design one would make these properties public but then not expect others to use them. It's scary because I don't think that intellisense should be filteringout legal things without making the user aware (see this previous post on that topic). I was thinking about doing something different so that this would be a lot clearer. My ideal solution would be to have the element in the completion list, but with a strikethrough through it. The tooltip would also say something along the lines of "Warning. The author of this component did not intend for it to be used externally" followed by the actual documentation on it. Unfortunately, it does not look like one can have that much control over the font in the completion list in VS2005. So, as an alternative, I could grey out the text and have the tooltip updated as well.

How do you feel about this? I might be personally biased here, but this "feature" really rubs me the wrong was and I definitely think we should do better. If we don't, I think we'll have a log of confused and irate developers on our hands.

Comments

  • Anonymous
    August 08, 2004
    I think greying it out makes sense. Strikethrough, though, would initially make me think that the method is deprecated, which is not the intention.
  • Anonymous
    August 08, 2004
    Ben: Fair enough. I was going for that "you really don't want to use this" type message.
  • Anonymous
    August 08, 2004
    I do like Dr Pizza's reply on your referenced post about this. If it sees you typing it and you can do it maybe not legally or maybe not a good idea then start popping it up. The other draw back to this is even right now if you type it. You get no intellisense help at all with any arguments and intellesesense is gone completely from any and all things having to do with that member.

    Like you said maybe you shouldn't use this method. Hmmm, but what if thats explicitly what you are planning to do and you are aware of what it does and this is what you want to do. I mean if this method is so bad to use why not let the compiler catch it? You would never do that because of the rare chance that someone is using something in a way MS never dreamed of. So why cut it from Intellisense?
  • Anonymous
    August 09, 2004
    Would it make sense to adopt the same approach as the menus in Windows and Office, i.e. hide them by default and have an icon at the bottom which expands to show all of them?
  • Anonymous
    August 09, 2004
    The comment has been removed
  • Anonymous
    August 09, 2004
    I think that any way of showing those methods in the editor will break their documentation.

    I also think that using attributes to get something like a "custom visibility" thru interaction with editor features is a bad design. Maybe you can dig and find out why does that attribute exist? Maybe it's obsolate? Maybe PrintPreviewDialog should be fixed?

    Or maybe my opinions are non-sense because I don't yet understand the "world of .net metadata".
  • Anonymous
    August 09, 2004
    BTW, I don't suggest "blame the others". From your entry it is apparent that you don't know exactly why is that attribute used (I may be wrong, though). What I suggest is that finding this out is an important step in solving the problem.
  • Anonymous
    August 09, 2004
    Radu: Why would it break their documentation?

    "I also think that using attributes to get something like a "custom visibility" thru interaction with editor features is a bad design"

    No arguments from me.

    ----

    However, the "why" is obvious. A developer out there decided that they wanted to have a public member that would only be used by certain people, not anyone generally consuming their code. It may be something that needs to be fixed, it may not. However, this attribute exists today and people are using it. The question is "what's the right way for us to listen to this attribute?" We've chosen a certain implementation now, but it is by no way necessarily the right one.
  • Anonymous
    August 09, 2004
    "Why would it break their documentation?"

    Well, you said that the documentation says: "The property or method is never browsable from within an editor". If you make it browsable (even by IntelliSense) you break this. It seems simple. Am I missing something?

    "A developer out there decided that they wanted to have a public member that would only be used by certain people, not anyone generally consuming their code"

    By "why" I mean: who's that develoder, why did (s)he decided somethink like this and who are those "certain people". My guess is that answering these questions can give you some hints on what is the correct course of action. Even if this a particular occurence of this problem, others might share some characteristics.

    Without knowing the answer to these questions, the grayed out solution sounds best.
  • Anonymous
    August 09, 2004
    Well, you do pose a good point, The Atribute is there to not show a method. But if I explicitly type in that method I would want the intellisense that goes with it. I guess thats my only problem with this. Once you type it in the editor then shows nothing.

    The only reason I bring it up is I have done this. I can't remember why, this was a long time ago I can't remember which project it was for. I was looking for a specific way to do something and this member allowed me to do it. I remember posting this question on windowsforms.net which intellesense wouldn't work with a specific member nor show up in intellesense. I never got any replies I even questioned if it was a bug or not. Obviously someone else thought it was a bug as well otherwise you wouldn't have been given the bug to look into.

    I looked through and read all the documentation on a method. So I looked it up, I understood what I was doing and still I wanted to do it. So I had to type everything in in and flip around to make sure I had all my arguments correct. I guess so maybe you leave it hidden. But if someone explicitly types it in then turn on the supporting intellisense for it. Does that model make more sense. Because if someone knows it is there. They have obviously done their homework on it and want to use it. I don't know it seems more to me this attribute is there more to protect the Mort and Elvis styles from doing something bad, but the Einstein type knows it is there and sees something there that may just suit his needs. Like I said I spent a lot of time trying to figure out why this one member wouldn't show up. I did everything from using Lutz reflector to decompile it to googling on it. So I really researched this method more than most typical ones where I read the MSDN on it and roll with it.
  • Anonymous
    August 09, 2004
    Sorry double post, I got a wierd BlogDoesNotExistException on first post change it tried again with same result. Yet they both posted. can you delete one of those. And this one.
  • Anonymous
    August 09, 2004
    Radu: Ah, i see. I was confusing the documentation for the EditorBrowsableState class and teh documentation for the CheckedListBox.DataSource propety.

    Note: the issue comes as to whether or not our implementation is the best for the user. "Not showing the member" is an example of a possible implementation of this API. We're considering alternative implementations that don't suffer from the same issues that arise from the current one.
  • Anonymous
    August 09, 2004
    Jeff: We will bind to the method just fine and will give you parameter help for it. All we currently do is hide it in the completion list.
  • Anonymous
    August 09, 2004
    Jeff: We will bind to the method just fine and will give you parameter help for it. All we currently do is hide it in the completion list.
  • Anonymous
    August 09, 2004
    The comment has been removed
  • Anonymous
    August 09, 2004
    The comment has been removed
  • Anonymous
    August 09, 2004
    The comment has been removed
  • Anonymous
    August 09, 2004
    The comment has been removed
  • Anonymous
    August 10, 2004
    Cyrus, I'm not exactly sure why you felt like repeating two times for me what the problem is, but I appreciate your patience :)
  • Anonymous
    August 11, 2004
    Now that .NET 2 supports friend-assemblies, Shouldn't all the public-but-not-intended-to-be-used members in the framework now be marked Obsolete and replaced with internal versions?

    Either that, or clean up the code, make the members fully public and not hidden, and write some good documentation.

    I don't see any in-between visibility. I understand the need for internal across assemblies, and while some argue that internal should never be used, I'm certainly not one of them.

    If people are actually using these methods (and I know they are, as I've seen several Internet posts about using certain unsupported public classes), and there are good reasons for them not to use them, then mark them Obsolete and give them a chance to stop using them.

    I at least hope that these not-so-public members have been tested for security flaws.
  • Anonymous
    August 12, 2004
    Sounds like the attribute EditorBrowsableState.Never needs to be deprecated. If you add another state to Intellisense that will only rarely appear then I think as end user I will just be confused. In fact knowing me I will spend hours googling 'intellisense grey'.

    Short of deprecating EditorBrowsableState.Never I don't see a clean solution.
  • Anonymous
    August 12, 2004
    Mark: I can think of at least one case where I'd use EditorBrowsableState.Never.

    If I were writing a Complex struct, I might want to provide as many overloaded operators as possible to as many different languages. If you follow CLS specs, it shouldn't be a problem if a language doesn't support all operators. If you write overloaded operators you're supposed to have alternate methods (usually well-named static methods) for non-operator-overloading languages. In the case of the exponent operator, I would most likely have a static Complex.Pow(Complex, Complex) method so that C# users could call operation. However, VB are able to use ^, so in VB I can have a Public Shared Complex Operator ^(Complex, Complex)

    However, it appears that under the current implementation, the method for this operator shows up in C# Intellisense, even though I'm providing an alternative. Using the attribute, the method should be able to be hidden from intellisense, although for me it still shows up (I don't know why).

    Speaking of which, if I were to be writing the Complex struct in C# (which I most likely would, being a C# programmer), there is currently no way I know of to mark the op_Exponent method as SpecialName so that VB can recognize it as an operator and consume it. I've posted this problem on the MSDN Feedback system, and it seems it has been turned over to the VB team for review (although I'm quite certain that it's a C# problem).

    http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=3d5f27e5-bfcb-45f4-84fd-b56323910906

    Maybe now I need to post another feedback report since EditorBrowsableState.Never isn't working in C# (it does work in VB, however).
  • Anonymous
    August 24, 2005
    You are the best. Thank you http://www.bignews.com