C#,将公共成员的方法设为私有

C#, making public members their methods private
2021-07-31
  •  译文(汉语)
  •  原文(英语)

我下面的课:

    public class Humptydump
    {
        public Humptydump()
        { }

        public Rectangle Rectangle { public get; private set; }

    }

在此类中,Rectangle类来自system.drawing,
我如何制作它,使人们无法访问矩形的方法,但可以获取矩形本身?

速聊1:
那没有道理.您不能使用一种类型的一半.您想解决什么问题?
速聊2:
据我所知,这是不可能的.当然,您可以只使用私有方法编写自己的类型.
解决过程1

在您的情况下,它将"正常工作".

由于Rectanglestruct,你的财产将返回一个复制Rectangle.因此,Rectangle除非您公开允许这样做的方法,否则任何人都不可能直接修改您的代码.

话虽这么说,一般来说,如果不提供对类型定义的方法的访问,就不可能提供对类型的访问.方法与类型一起使用.在这些情况下,唯一的选择是创建一个新类型,该新类型公开您选择的数据,而不提供您希望公开的数据或方法,并提供对此类型的访问.

速聊1:
更确切地说,Rectangle是一个邪恶的可变结构.
速聊2:
不过,仍然没有关系,因为您无法更改类中包含的结构...
解决过程2

如果矩形不是一个结构,则可能会派生它并隐藏这些方法:

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
    }
}
解决过程3

您是在Rectangle专门讨论对象还是用更笼统的术语谈论对象?

如果您使用的是更笼统的术语,那么重构模式中经常会出现这种情况.这最常见于对象的集合.例如,如果您公开a,List<T>那么即使setter是私有的,人们仍然可以通过getter修改集合,因为这样做时他们实际上并没有设置集合.

要解决此问题,请考虑Demeter定律.也就是说,当某人与某个对象公开的集合进行交互时,他们是否真的应该与该对象本身进行交互?如果是这样,则不应公开集合,而对象应该公开其需要的功能.

因此,对于集合来说,您可能最终会得到如下所示的结果:

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
    }
}

当然,您可能还希望公开对象本身的某些副本,以供人们阅读,而不需要修改.对于集合,我可能会执行以下操作:

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

这样,任何人都可以看到对象的当前状态并枚举它们,但是他们实际上不能对其进行修改.不是因为它没有设置器,而是因为IEnumerable<T>接口没有用于修改枚举的选项.仅用于枚举.

对于您的情况Rectangle(或类似的东西,无论如何还不是已经通过值传递的结构),您将做一些非常类似的事情.存储一个私有对象并提供公共功能以通过类本身对其进行修改(因为我们正在谈论的是该类需要知道何时修改其成员),以及检查该对象的功能而无法修改正在使用的对象检查.可能是这样的:

class SomeObject
{
    private AnotherObject Thing;

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

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

    // etc.
}

在这种情况下,无需过多介绍什么AnotherObject(因此可以从某种角度考虑使用伪代码),检查内部对象的属性将返回其副本,而不是对实际对象的实际引用.对于值类型,这是语言的默认行为.对于引用类型,您可能需要在性能和性能之间取得平衡(如果创建副本是一项繁重的操作).

在这种情况下,您还需要注意使对象的界面不直观.消费代码可能期望能够修改被检查的内部对象,因为它公开了修改自身的功能.而且的确,他们可以修改他们拥有的副本.如何解决这个问题在很大程度上取决于对象的概念性质以及它们之间的关系,这是一个精心设计的示例并没有真正传达出来的内容.您可能会创建一个自定义DTO(甚至是一个结构),该DTO仅返回内部对象的可观察属性,从而使它更明显是副本而不是原始对象.您可能只是说这是智能感知注释中的副本.您可以设置单独的属性以返回内部对象的各个数据元素,而不是单个属性以返回对象本身.有很多选项,由您决定什么对您的对象最有意义.

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?

Talk1:
That doesn't make sense. You cannot use half of a type. What problem are you trying to solve?
Talk2:
As far as I know it is not possible to prevent that. You could of course write your own type with only private methods.
Solutions1

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.

Talk1:
More precisely, Rectangle is an evil mutable struct.
Talk2:
Still doesn't matter, though, since you can't mutate the struct contained within the class...
Solutions2

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
    }
}
Solutions3

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.

转载于:https://stackoverflow.com/questions/17069982/c-making-public-members-their-methods-private

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入