25
public class Demo
{
    private List<string> _items;
    private List<string> Items
    {
        get
        {
            if (_items == null)
                _items = ExpensiveOperation();

            return _items;
        }
    }
}

Other methods in the Demo class will have access to the _items field. Since I'm using a property to lazy load the items, I do not want another developer to mistakenly try to use the _items field.

I know there is the ObsoleteAttribute that I may use, but this field isn't technically obsolete.

Is there a better way to mark a member as "do not use"?

Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
nivlam
  • 3,223
  • 4
  • 30
  • 39
  • 27
    If you don't trust the developers on your team, you have bigger problems to worry about. – jason Jan 22 '12 at 21:55
  • I think if you are that worried about it you should hide items behind another layer of abstraction where you can hide the private members from general use. – J. Holmes Jan 22 '12 at 21:55
  • 19
    It is private. The buck stops there. If more than one developer works on the private parts of a class then they ought to communicate really well. At least a dinner and a movie. Not something you ever can enforce, you can only avoid it by good design. – Hans Passant Jan 22 '12 at 21:56
  • 4
    Comments go quite a long way towards solving this kind of issue! – spender Jan 22 '12 at 22:12
  • 3
    @Jason You're right, in that line of thinking we should make every property/field/method public and just trust the other developers. – Rob Jan 22 '12 at 22:59
  • 1
    @Rob: Either you're being sarcastic or you completely missed the point. – jason Jan 22 '12 at 23:12
  • 1
    @Jason I was clearly being sarcastic in response to your comment saying that access modifiers don't really matter - you should just trust your team. – Rob Jan 22 '12 at 23:18
  • 2
    @Rob: But I did not say that access modifiers don't matter. I never considered the possibility that you were both being sarcastic and completely missed the point. – jason Jan 22 '12 at 23:27
  • 1
    @Jason The question is about access modifiers (or atleast a workaround) in this particular case. You're saying he should just trust his team instead. I'm not quite understanding your confusion here. – Rob Jan 22 '12 at 23:53
  • @Rob: I'm not the one that is confused here; you simply don't understand what I'm saying. I did not say that he should trust his team instead of using access modifiers, which is what your previous two comments are implying that I said. Again: I did not say and I am not saying that trust is a replacement for access modifiers. You keep putting words in my mouth that I neither said directly nor implied. – jason Jan 23 '12 at 00:05
  • @Jason Then could you explain the difference betwen the two? He never said he didn't trust his team either. – Rob Jan 23 '12 at 00:06
  • @Rob: He's trying to solve a problem he wouldn't have if he did trust his team. – jason Jan 23 '12 at 00:14
  • 3
    @Jason, I’m afraid you are wrong. Depending on what you mean by “trust”, I trust my team completely to be competent and not malicious; but I don’t naïvely think they are all perfect and never make mistakes. Hence, this is a valid question, and I think that access modifiers in C# are crude and insufficient because it allows reasonable everyday mistakes to go unnoticed when they *could* be automatically detected with a minimum of support from the compiler. – Timwi Jan 25 '12 at 20:05

7 Answers7

48

Though it's not a general technique for what you want to do (and there isn't one and, as the other answers cover, you need to trust other devs), in this instance, you could create a Lazy<List<T>> (assuming .NET 4 or later - though it's easy to backport)

class Demo {
    readonly Lazy<List<string>> _items;
    public Demo() {
        var _items = new Lazy<List<string>>( ExpensiveOperation);
    }
    List<string> Items { get { return _items.Value; }}
 }

The readonly / non-mutable approach is generally the way to go for backing fields either way.

EDIT: Based on @Timwi's answer (go +1 if you like the idea) one can go to town on it, and in a JavaScript stylee use capability-based restriction to not even expose the Lazy field, just an operation closed over it (Also incorporates @Mr Disappointment's ReadOnlyCollection suggestion):

class Demo {
    readonly Func<ReadOnlyCollection<string>> _getItems;
    public Demo() {
        var items = new Lazy<List<string>>( ExpensiveOperation);
        _getItems = () => items.Value.AsReadOnly();
    }
    ReadOnlyCollection<string> Items { get { return _getItems(); }}
 }

And thus endeth our stupid coding tricks post.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • 3
    I think that's the right way, as it dismisses usage of a field that can be potentially misused – flq Jan 22 '12 at 21:56
  • 6
    Yes, while other developers can still access `_items` directly, it doesn't matter. The field cannot be overwritten (it is `readonly`), and the initialization logic is guaranteed to be run by the `Lazy` class. Also consider supplying `LazyThreadSafetyMode.ExecutionAndPublication` to the constructor if `ExpensiveOperation` should only ever be executed once, even if the field is accessed by multiple threads simultaneously. – porges Jan 22 '12 at 22:02
  • 1
    I'm down with this way of doing things. Avoids any possible confusion down the line (rather than relying on some useless future dev to actually read anything). However, I have to question now what prevents this same dev from simply calling `ExpensiveOperation` directly. – spender Jan 22 '12 at 22:07
  • 2
    Isn't this just making it complex-looking enough for the developer to take a second glance? It only restricts reassignment of `_items` and its underlying list, meaning elements can still be manipulated. And this could be achieved with `readonly List _items` and populating on demand. Perhaps `readonly ReadOnlyCollection` should be used. – Grant Thomas Jan 22 '12 at 22:28
  • @Porges: I'm pretty sure (docs and Reflector say so) [that's actually the default](http://msdn.microsoft.com/en-us/library/dd642329.aspx) for this style of initialization. Pity they don't have a `Lazy.Create*` factory or something to make the thread safety aspect clearer to avoud this type of confusion. – Ruben Bartelink Jan 22 '12 at 23:47
  • @Mr Disappointment: Valid point, but didn't want to make things even more complex - remember the property wasn't even `public` in the OP's version (which is what would decide making it a `ReadOnly` for me in my code). – Ruben Bartelink Jan 22 '12 at 23:50
  • @RubenBartelink: For some reason I thought the default was `PublicationOnly`. Thanks. – porges Jan 23 '12 at 01:05
  • @Porges: There's lots of cases where you don't get that level of locking - [ConcurrentDictionary.GetOrAdd is one](http://kozmic.pl/2010/08/06/concurrentdictionary-in-net-4-not-what-you-would-expect/) (Though in that case it's because there are lock free algorithms at work so the guarantee could not be achieved within the same order of magnitude of performance) – Ruben Bartelink Jan 23 '12 at 08:26
  • 2
    “[...] and there isn't one and, as the other answers cover, you need to trust other devs” — This is not true, see my answer. – Timwi Jan 25 '12 at 20:39
  • @Timwi: Ah, nifty JavaScript techniques. Nice, but this approach boils down to the same thing and is more idiomatic .NET [4] IMO - while an experienced C# dev will undersand the scoping and be able to spot trouble during refactoring, it's simply more error prone doing it long hand when there's a named concept/pattern and built in BCL class that can do it more neatly. (BTW I'm baffled as to how this post is getting such a ludicrous number of upvotes) – Ruben Bartelink Jan 25 '12 at 20:58
45

Rename the _items field to _heyFutureDeveloperDoNotReferenceThisFieldMmmkay

Ian Nelson
  • 57,123
  • 20
  • 76
  • 103
12

If you set such an attribute, then how would the Items getter access it without generating the same warning/error that whatever you're looking for would generate?

What do you mean by "another developer?" If you mean another developer working on this same code (with you), then a simple comment like:

///<summary>Do not access directly, using lazy initialization in getter.</summary>

should suffice, as Visual Studio will show that whenever hovering over the field.

If you mean someone using this class, then that is the whole point of information hiding, and you are good to go.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • “how would the `Items` getter access it without generating the same warning” — Well, with `#pragma disable`, but I agree it’s not great. – Timwi Jun 07 '14 at 09:27
6

Yes, there is a relatively simple way. Some might think of it as a hack, but I think it is legitimate. It uses the local-variable scoping rules to achieve the method-level privacy you desire:

public class Demo
{
    private readonly Func<List<string>> _getItems;

    public Demo()
    {
        List<string> items = null;
        _getItems = () =>
        {
            if (items == null)
                items = ExpensiveOperation();
            return items;
        };
    }

    public List<string> Items { get { return _getItems(); } }
}

Now the variable items is correctly scoped to the method that uses it. It is still possible to access _getItems, but doing so is inconsequential because it does exactly the same thing as Items. It is not possible to modify items because it is local or _getItems because it is readonly.

Timwi
  • 65,159
  • 33
  • 165
  • 230
4

I happen think this is a very valid thing to want to do. Unfortunately, C# wasn't designed with this in mind. So there isn't that much you can really do about it, in practice, in the current version of the language.

If you don't trust the developers on your team, you have bigger problems to worry about.

Strong disagree; if you trust anyone, even yourself, that is when you have a problem. The best code doesn't trust anyone. The best code is bullet-proof. It leaves no way for anyone to screw up.

C# doesn't quite make this possible, though it comes closer than many other languages.

It is private. The buck stops there. If more than one developer works on the private parts of a class then they ought to communicate really well.

Basically the same argument. Yes, it's private, but so what? Why is it not a valid thing to want to encapsulate private details well?

P.S. I've suggested a related (but not quite directly relevant) practical approach to enable better bullet-proofing of code in C# but I don't think many people have seen it. So here goes :) I'd love to see a practical approach for encapsulating private members.

Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
1

Do absolutely nothing.

With a public or protected member of a well-written class, we would expect accessing it to work in a sensible way and a case where that was not true should be well documented.

With a private field, there's no reason why we would make such an assumption.

Further, if I come to this class as a new developer on the team, I don't know what _items does. What am I going to do with it? There isn't any meaningful job I can do until I've looked at what existing code does with it. And I'm going to see that it's the backing field for a lazy loaded property. All the more so if there's even a tiny bit of documenting comments.

It's not like you can just randomly do whatever you want with other private fields and expect it to work.

Ian Nelson
  • 57,123
  • 20
  • 76
  • 103
Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
-2

How about

private Dictionary<String,Object> PandorasCoochie = new Dictionary<String,Object>()

Then putting your untouchable property backers in there.

Mark Robbins
  • 2,427
  • 3
  • 24
  • 33