Freigeben über


internal = public?

There was an interesting thread this week inside the firewall about compatibility concerns the .NET Framework (and by extension WinFX) has in light of the fact that you can you use reflection to find and even invoke private members. Here is the exact question:

What is our BREAKING CHANGES policy towards applications that call internal methods in our assemblies through Reflection? Are we obligated to be backwards compatible with such apps between versions, meaning no changes to internal methods (spec or behavior wise) in our assemblies?

Writing an application that depends on internal implementation details, even if they happen to be exposes via reflection, is not a very wise thing. Even the book on the subject Hijacking .Net makes it clear that this technique should be very carefully used.

That said, other folks on the thread pointed out that judging from the QFEs and other customer reports we get an increasing number of folks are using private reflection in really important applications. Does this mean even implementation details of the framework have to remain unchanged across versions? That would seriously impair our ability to improve the platform over time and I don’t think this is our customer’s interests. For those of you using private reflection to access implementation details of the framework do you expect those applications to keep working on newer versions of the .NET Framework or would you rather see us keep even internal details unchanged over time?

On the CLR team, we've speculated (just speculation, no firm plans here at all) about whether we can make a breaking change to restrict any use of Reflection MemberAccess to some limited supportable scenarios. For instance, we might prevent serializers from using private reflection technique except on members that are explicitly earmarked for serialization. We would love to get any information you have on how your customers (or your own products) are actually using private reflection. If anyone knows of such cases, please comment of drop me a line with any details you have.

Comments

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 07, 2004
    Why is it even possible to do this? What's the point of scope access keywords, if they aren't enforced by the runtime?

  • Anonymous
    February 07, 2004
    Focus on exposing more frunctionality so that people no longer need to use reflection to access private members, rather than trying to stop code from breaking.

    It should be obvious to any developer that if you grab private members, you could break if those members disappear.

  • Anonymous
    February 07, 2004
    I can't disagree more with the earlier comment that the ability to reflect private members is non-issue.

    The decision to allow public access to private members via reflection was an INCREDIBLY bad choice because it affects everyone who writes code for this environment. We all have to worry about whether some idiot (uninformed or malicious) will break our code via reflected access to the a private method. Having to worry about missuse of private methods every time you design a class is a phenomenal waste of developer time (either when you design the class or when you have to fix the pieces later).

    I wholeheartedly support the proposal to limit reflection of private members to an explicitly marked subset.

  • Anonymous
    February 07, 2004
    Do not limit the future flexibility of the framework because a certain few people use reflection to access private-scope methods/variables. They can use side-by-side versioning features to keep their app working.

  • Anonymous
    February 07, 2004

    Don mentioned above that it was an INCREDIBLY bad choice. I don't disagree; it is too easy and when I first learned about it I wondered why they even bothered allowing it. I would support this functionality being removed.

    That said, you can always have your code hijacked. Someone hosting the CLR or hooking it or hacking it can always get at your implementation. They can override security and change the metadata of your assembly. Just as they can have unsafe code and call native code.

    It appears to me that the real issue (and this is just opinion based on my experience), is that Code Access Security hasn't panned out as well as it could. There's no incentive for an app writer to write an application that has less than full trust, because users are used to native apps that need full trust anyway.

    Hopefully Longhorn really starts addressing this, as managed code proliferates and things like ClickOnce increase the demand for partial-trust apps. We'll see though; customers don't like complicated security stories, and are eager to override secure defaults if it lets them run an app they want to see.

  • Anonymous
    February 07, 2004
    I would also agree with you shouldn't be allowed to access private methods by any means, including reflection.

    As for introducing a breaking change by fixing this, I would say go for it. I would hope that anyone using reflection to get at private methods would have enough sense to realize that this may or may not work in the future. Besides, if they absolutely positively must use some random private method in the BCL, then let them stay with v1.1 of the Framework.

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 07, 2004
    We used reflection to tweak your private and internal bits in at least ten places in a large COTS app to work around bugs in the .NET Framework code.

    I expect these fixes will break when the framework changes. No biggie, provided that you fix the bugs that caused me to do this.

    Just keep in mind that not everybody that's doing this is evil. We just didn't have much choice.

    Dejan

  • Anonymous
    February 07, 2004
    I think internal, protected and private methods should be allowed to be reflected on. After all, reflection is not about encapsulated access to an object, it is about looking at the internal details of an object. If you want to stick to safe, encapsulated OO programming practices, use the public interface only.

    At the same time, it should be made clear that any code that uses private implementation through reflection can and most likely will break without further notice.

    Uninformed and malicious users have always been around. Even if reflection may make their job of wreaking havoc marginally easier, I don't think it changes it that much. They were able to wreak havoc with our code even in the unmanaged world.

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 07, 2004
    I would definitely support not being able to reflect over private members unless they are marked with some kind of reflectable attribute.

  • Anonymous
    February 07, 2004
    Please don't try to maintain backwards compatibility for code that reflects against implementation details.

    I would be happier if you deliberately changed the names of all private members with each new version of the .NET Framework - that way you would establish a good precedent: everyone would then know their code is definitely going to break when the next version comes out. (It'd be reasonable to maintain the names across service packs on a particular major.minor release though - that way at least we can rely on side-by-side framework installation in the scenarios where we are forced to use such crufty code...)

    Of course the obvious way to change all the names would be to run the .NET Framework through an obfuscator. I'd prefer it if you didn't do that though - the ability to grok the FCL with ILDASM has certainly made it much easier for me to learn how to use .NET. I'd hate that to go away in future versions.

    Also, I disagree with those who argue that we shouldn't be able to reflect against these things in the first place. There are legitimate uses for this, as some have already pointed out in this discussion; I won't repeat them, I just wanted to cast my -1 here.

  • Anonymous
    February 07, 2004
    The comment has been removed

  • Anonymous
    February 08, 2004
    I dont agree
    I have a few cases of private access for the same reasons with Dejan and RichB (fix FCL bugs). Those may be fixed, in a future version but i am sure that others will surface. Since MS insist on not providing the FCL source code (irrational imho) must provide alternatives.

    Ian : I hope that Mono will be mature enough, the day that MS will release an obfuscated FCL ;)

  • Anonymous
    February 08, 2004
    I agree that MS is free to change private/internal implementation and is not responsible for apps who rely on them.
    But on the other hand, I don't want reflection to private members prohibited. I have classes I want their constructors private. Within the assembly, I have a class that creates one of those classes. The class has a list of Type, and invokes constructors via reflection. This is a valid use of private reflection, isn't this.

  • Anonymous
    February 08, 2004
    Again, what do you expect to use to get access to the private members in a debugger? How do you profile these if theyre not available via reflection? You have yet to answer that. Well I say do it then, remove it and you can code blind. Lets see how far you get.

  • Anonymous
    February 08, 2004
    I suggest allowing access to these methods if and only if the methods are contained in a debug-mode assembly (and include attributes -- maybe one called ReflectionAccessAttribute... that way one could prevent even the enumeration of method names if they wanted).

    Past this, intentionally break applications which call internal methods. In the short term it will be unpleasant (but you have versioning, as has been mentioned, so it isn't that big of an issue) but if you don't do this you're in for a world of hurt, as developers will then get the idea that it's a safe thing to do. If code which calls internal methods breaks consistently, it will quickly become obvious that calling internal methods is a big no-no. Some have mentioned that calling internal methods can help work around bugs. That may be so, but working around bugs in this manner, in the long term, hurts the Framework as a whole. It will become dirty and unchangeable. Yes, it helps one developer, but it does not help the entire developer community.

  • Anonymous
    February 08, 2004
    The comment has been removed

  • Anonymous
    February 08, 2004
    The comment has been removed

  • Anonymous
    February 08, 2004
    Don't break the ability to call private methods! But also, do not worry about breaking apps that do this. Anyone who has done this has done it in the full knowledge that what they are doing is not what was intended.

    Concentrate most on removing the reasons making us want to do this. The only time I have ever done this in production code is to get round a bug (/ problem) in the framework classes.

    E.g.

    the documentation for TreeNode.Collapse says:

    "The Collapse method only collapses the current TreeNode; child tree nodes are not collapsed."

    This is not what happens in practice (at least not in framework 1.0), in practice child tree nodes are also collapsed. Which is bizarre, since this implementation is more code and harder work than the simpler as per documentation case. Take a look at the IL - why does it do that?

    And if you want to just collapse the node and not the children, without manually recording the state of all child nodes pre-collpase and restoring post-collapse, the simplest implementation is something like this:

    MethodInfo mi = typeof(TreeNode).GetMethod("DoCollapse",
    BindingFlags.Instance | BindingFlags.NonPublic,
    null, new Type[]{typeof(TreeView)}, null);

    if (mi != null) {
    mi.Invoke(node, new object[]{this});
    }

    Now. If that sort of bug wasn't there, I'd have no reason to go calling private methods. I'm prefectly prepared for my code to break in future versions of the framework, there's an easy fix, and my code documentation tells me exactly what I've done and why. But if it breaks because you've taken away my ability to call private methods, rather than because you've fixed the original bug, I will be irritated.

    Regards,

    Sam

  • Anonymous
    February 08, 2004
    +1 for not disabling private reflection. Instead, fix the bugs and/or expose the functionality people are trying to use as public, supported code. Reflection is not the problem, it's the sealed/non-virtual/private nature of so much of the framework classes.

    Jim

  • Anonymous
    February 08, 2004
    If you disable that you ruin my buisness products, I will no longer support my developer tools on .NET and C#.

    I will move my products away from .NET.

  • Anonymous
    February 08, 2004
    We make developer tools and profilers and debugging tools, I guess you dont want those if you do this.

    Its ok, we can get money from non .NET houses.

  • Anonymous
    February 08, 2004
    We make developer tools and profilers and debugging tools, I guess you dont want those if you do this.

    Its ok, we can get money from non .NET houses.

  • Anonymous
    February 08, 2004
    I don't see why support for debugging/profiling tools couldn't be handled in a similar way to how these tools worked for unmanaged C++. By emitting (or exposing) the relevant information with an 'export debug information' option. Though as I don't write such tools, I don't know if that solves all your problems (and it doesn't sound like a minor change either).

    I currently use reflection for enumerating and creating classes that implement specific interfaces (for plug-in support). In my own plugins I generally flag them as internal (so they are not easily exposed simply by linking to the assembly). Though I personally wouldn't mind if the ability to reflect on privateinternal items was restrictedchangedmoved, some way of exposing items would be appreciated (I'd guess an 'EnableReflectionAttribute' of some-sort) for times when you do actually want them to be reflected dispite their access flags.

    Indeed, the 'export debug information' option I mentioned earlier could simply mean all items are implicitly flagged with the attribute. When a release build is made such information is removed.

    n!

  • Anonymous
    February 08, 2004
    The comment has been removed

  • Anonymous
    February 08, 2004
    Reflection is one of the many good aspects of having C# and the CLR.

  • Anonymous
    February 08, 2004
    I don't think anyone mentioned 'killing' reflection?

    n!

  • Anonymous
    February 08, 2004
    The comment has been removed

  • Anonymous
    February 08, 2004
    That was me who mentioned debug builds? And I didn't mean 'debug builds' only, maybe I should rephrase myself. I meant 'debug info' which is entirely different (you can have debug info in release builds) and it was only a suggestion. It could be implemented in other ways too, having a special assembly flag that make all items reflectable for instance (though it would have to be more secure than a simple flag, to prevent anyone simply setting it).

    I fail to see how attributes affect the code that gets shipped, it doesn't affect the code-paths taken during runtime (except for the attribute constructor called by the 'host' application when the attributes are accessed). As I said, even if that's still not good enough, there are other ways.

    I thought the original point was that reflection enables people to do bad things, what do people think of limiting reflection. Even to the scope of having coders explicitly tag privateinternal items as 'reflectable' (which, I guess, implies the use of an attribute). The majority of the time I add a privateinternal item I really do want it privateinternal (ie. I would prefer it couldn't be reflected). Having the option would certainly make me happy and give more control over the assembly to the developer.

    n!

  • Anonymous
    February 08, 2004
    Any changes to code mean its a different product mathmatically.

    It may be similar but infact its not what you ship, we all know the bugs that arise from a release build that dont show up in a debug build on the unmanaged world for example due to the fact that memory layout is different.

    Simple fact is, its not broken, it works as it should and the only people that I see complaining are those that cannot understand the tools and want Develop By Numbers by Big Bird.

  • Anonymous
    February 08, 2004
    Yes, but adding an attribute does not change the code. It does add new attributes of course, but the executing of the application is not affected.

    If you're simply referring to the fact that the attribute is taking up memory and thus has changed the memory layout of the application, it should be noted the JIT process amongst other things makes the memory layout extremely volatile anyway. Saying all that, there are other ways of doing that doesn't even require attributes applied to everything.

    I'm not sure if your last statement was for or against something :)

    n!

  • Anonymous
    February 09, 2004
    The comment has been removed

  • Anonymous
    February 09, 2004
    There is already languages for people like that, its called BBC Basic

  • Anonymous
    February 09, 2004
    The comment has been removed

  • Anonymous
    February 09, 2004
    I'm not sure where anyone has mentioned 'dumbing' down the language, it's simply offering more control to the developer (which, if you think about it, makes it more complex).

    n!

  • Anonymous
    February 09, 2004
    As for the JIT affecting memory layout , its deterministic like youre program. If you follow the same code path etc you will have the same memory layout

  • Anonymous
    February 09, 2004
    Ian++.

  • Anonymous
    February 09, 2004
    The JIT doesn't guarantee deterministic memory layout, it can put your code anywhere it likes.

    And this is all veering steeply away from the topic, there are other ways to provide such debug information without adding attributes everywhere.

    n!

  • Anonymous
    February 09, 2004
    Yes but if everything was done EXACTLY the same as the last run it would end up the same. System was the same, state the same the hoopla exactly the same yes it would. If not then its a RANDOM JIT and no Logic whatsoever.

  • Anonymous
    February 09, 2004
    Well, just to add to the cacophony..

    I think relfection of private/internal has its uses, but I don't think MS should think twice about breaking changes for those. Don't hold all your customers back for the few that are using non-public interfaces extensively.

  • Anonymous
    February 09, 2004
    Breaking changes in this case actually sounds like a good idea to me. The multiple benefits including keeping the framework flexible, motivating better bug reporting, motivating better programming habits, etc.

    In a similar vein, I prefer keeping reflection available to those who wish to use it. Intentionally limiting the power of any tool seems to me the surest way to lose its developer base.

  • Anonymous
    February 09, 2004
    As soon as I see C# becomming dummed down, I walk or I split the compiler using other sources (mono or whatever).

  • Anonymous
    February 09, 2004
    I do not mind you breaking code that uses reflection when you do a major new release, .e.g. version 1.2. You should however not break such code when you do a service pack.

    The questions is, was 1.1 a service pack, or a major new release.

    I do not even mind you change some of the APIs for major release, a day or two to porting to get my code to work with version 1.2 is not a problem. Provided that the changes I need to made also work with version 1.1 (using #if is OK at times).

  • Anonymous
    February 09, 2004
    The comment has been removed

  • Anonymous
    February 09, 2004
    The comment has been removed

  • Anonymous
    February 10, 2004
    The comment has been removed

  • Anonymous
    February 10, 2004
    The comment has been removed

  • Anonymous
    February 11, 2004
    The comment has been removed

  • Anonymous
    February 12, 2004
    The comment has been removed

  • Anonymous
    February 23, 2004
    Beeing able to access private members of a class is plain out silly.
    I dont understand how any sane person could design the framework that way.

  • Anonymous
    June 02, 2009
    PingBack from http://hammockstandsite.info/story.php?id=18250

  • Anonymous
    June 14, 2009
    PingBack from http://cutebirdbaths.info/story.php?id=1425