简体   繁体   中英

C#, making public members their methods private

I the following class:

    public class Humptydump
    {
        public Humptydump()
        { }

        public Rectangle Rectangle { public get; private set; }

    }

in this class the Rectangle class comes from system.drawing,
how do i make it so people cannot access the methods of the rectangle, but can get the rectangle itself?

In your case, it will "just work".

Since Rectangle is a struct , your property will return a copy of the Rectangle . As such, it will be impossible for anybody to modify your Rectangle directly unless you expose methods to allow this.

That being said, it's impossible, in general, to provide access to a type without also providing access to methods defined on the type. The methods go along with the type. The only alternative in those cases would be to create a new type that exposed the data you choose without the data or methods you wish to be exposed, and provide access to that.

If rectangle was not a struct, one possible thing would be deriving it and hiding those methods:

public class DerivedClass : BaseClass
{

    new private SomeReturnType SomeMethodFromBaseClasse(SameParametersAsInBaseClassAndSameSignature
    {
        //this simply hides the method from the user
        //but user will still have the chance to cast to the BaseClass and
        //access the methods from there
    }
}

Are you talking about the Rectangle object specifically, or on a more general term and just using that as an example?

If you're talking on a more general term, this is something that comes up very often in refactoring patterns. This most commonly happens with collections on objects. If you expose, for example, a List<T> then even if the setter is private then people can still modify the collection through the getter, since they're not actually setting the collection when they do so.

To address this, consider the Law of Demeter . That is, when someone is interacting with a collection exposed by an object, should they really be interacting with the object itself? If so, then the collection shouldn't be exposed and instead the object should expose the functionality it needs to.

So, again in the case of a collection, you might end up with something like this:

class SomeObject
{
    private List<AnotherObject> Things;

    public void AddAnotherObject(AnotherObject obj)
    {
        // Add it to the list
    }

    public void RemoveAnotherObject(AnotherObject obj)
    {
        // Remove it from the list
    }
}

Of course, you may also want to expose some copy of the object itself for people to read, but not modify. For a collection I might do something like this:

public IEnumerable<AnotherObject> TheObjects
{
    get { return Things; }
}

That way anybody can see the current state of the objects and enumerate over them, but they can't actually modify it. Not because it doesn't have a setter, but because the IEnumerable<T> interface doesn't have options to modify the enumeration. Only to enumerate over it.

For your case with Rectangle (or something similar which isn't already a struct that's passed by value anyway), you would do something very similar. Store a private object and provide public functionality to modify it through the class itself (since what we're talking about is that the class needs to know when its members are modified) as well as functionality to inspect it without being able to modify what's being inspected. Something like this, perhaps:

class SomeObject
{
    private AnotherObject Thing;

    public AnotherObject TheThing
    {
        get { return Thing.Copy(); }
    }

    public void RenameThing(string name)
    {
        Thing.Name = name;
    }

    // etc.
}

In this case, without going into too much detail about what AnotherObject is (so consider this in some ways pseudo-code), the property to inspect the inner object returns a copy of it, not the actual reference to the actual object. For value types, this is the default behavior of the language. For reference types, you may need to strike a balance between this and performance (if creating a copy is a heavy operation).

In this case you'll also want to be careful of making the interface of your object unintuitive. Consuming code might expect to be able to modify the inner object being inspected, since it exposes functionality to modify itself. And, indeed, they can modify the copy that they have. How you address this depends heavily on the conceptual nature of the objects and how they relate to one another, which a contrived example doesn't really convey. You might create a custom DTO (even a struct) which returns only the observable properties of the inner object, making it more obvious that it's a copy and not the original. You might just say that it's a copy in the intellisense comments. You might make separate properties to return individual data elements of the inner object instead of a single property to return the object itself. There are plenty of options, it's up to you to determine what makes the most sense for your objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM