tags:

views:

298

answers:

2

Basically what I'm hoping for is something that would work like how the Obsolete attribute works with Intellisense and strikes the method text when typing out the name. What I'm looking for is an attribute that blocks the method from being seen with the assembly it's defined. Kind of like an reverse internal. Using 3.5 by the by.

Yeah sounds odd but if you need the reason why, here it is:

My current solution for lazy loading in entity framework involves having the generated many to one or one to one properties be internal and have a facade? property that is public and basically loads the internal property's value:

public ChatRoom ParentRoom
{
  get
  {
    if(!ParentRoomInnerReference.IsLoaded)
    {
       ParentRoomInnerReference.Load();
    }

    return ParentRoomInner;
  }   

  set
  {
    ParentRoomInner = value;  
  }
}

Problem with this is if someone tries to use the ParentRoom property in a query:

context.ChatItem.Where(item => item.ParentRoom.Id = someId)

This will blow up since it doesn't know what to do with the facade property when evaluating the expression. This isn't a huge problem since the ParentRoomInner property can be used and queries are only in the entity assembly. (IE no selects and such in the UI assembly) The only situation comes in the entity assembly since it can see both properties and it's possible that someone might forget and use the above query and blow up at runtime.

So it would be nice if there were an attribute or some way to stop the entity assembly from seeing (ie blocked by intellisense) the outward facing properties.

Basically inside the assembly see ParentRoomInner. Outside the assembly see ParentRoom. Going to guess this isn't possible but worth a try.

I do see that there is an attribute for stopping methods from being viewable (System.ComponentModel.EditorBrowsable) but it's choices are rather slim and don't really help.

+1  A: 

I haven't heard of a good way to do this in plain .NET. But, here are some ideas. Maybe one of them will work, or set you off in a direction that will be helpful.

  • Use FxCop, probably writing your own rule to make sure ParentRoom isn't called from the asslembly that defined it.
  • Look into the various post-processing projects for .NET (link design-by-contract).
  • Write some code inside your ParentRoom getter which will check the stack (using "new Stack()" or "new StackFrame(1)" to figure out whether the caller was from the same assembly. If so, either throw an exception or simply return ParentRoomInner.
John Fisher
Third would essentially be a runtime check though, right? Not sure this would work with entity framework and evaluating expressions or would suppose that I would be sending back a pointer to the ParentRoomInner property which would basically change the property signature right?
Programmin Tool
If your code determines that it has been called by the same assembly, it would simply "return ParentRoomInner;", skipping the "ParentRoomInnerReference" code. It wouldn't change the property signature (at least not from what I read above).
John Fisher
+1  A: 

You can use the EditorBrowsableAttribute for this:


[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void MyMethod() {}

One thing to know, though: In c#, you will still get intellisense on the method if it is in the same assembly as the one you are working in. Someone referencing your assembly (or your project, for a project reference) will not see it though. You can also pass EditorBrowsableState.Advanced, and then you will only get intellisense if c# if you clear the HideAdvancedMembers option in Tools Options.

JMarsch
Problem is this would essentially be like internal. This is more like reverse internal. I don't want Intellisense to show it within the parent assembly, but everywhere else.
Programmin Tool
Oh, I see -- this is some kind of external API, not to be used within the assembly, but for use by external clients.That's a tough order, I'm afraid. You could define the methods that are to be external only as an interface, and then implement those methods explicitely. They would only be visible if you cast your object to that interface. This would mean significant changes to your API (probably) you would always expose the class as the interface externally, and use it as a class internally. Of course, there's nothing to stop the internal user from retrieving it with the external call.
JMarsch
Yeah problem is I want to make the cake and eat it too. It's not end of the world by any means. Just was hoping there might be a way to pull this off.
Programmin Tool