一种类型如何访问另一种类型的属性的私有设置器?
我所需要的只是一种方法,使一个类的属性只能从另一个类(一种管理器类)“设置”。
这在 C# 中可能吗?
我的同事“可靠”地告诉我,我有一个设计缺陷,但我觉得我至少应该在认输之前询问社区!
All I need is a way to make a property of one class only 'settable' from one other class (a sort of manager class).
Is this even possible in c#?
My colleague 'reliably' informs me that I have a design flaw, but I feel I should at least ask the community before I concede defeat!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
不,在 C# 中实际上不可能以任何干净的方式做到这一点。 你可能有一个设计缺陷;-)
No, it's not really possible to do this in any clean way in C#. You probably have a design flaw ;-)
您可以使用
internal
修饰符,它允许同一程序集中的所有类型访问数据(如果使用[InternalsVisibleTo]
,则可以访问指定程序集 - 但不行:没有friend
相当于 C# 中的内容:
You can use the
internal
modifier, which lets all types in the same assembly access the data (or nominated assemblies if using[InternalsVisibleTo]
- but no: there is nofriend
equivalent in C#.For example:
你有一个设计缺陷。 另外,不要对数据隐藏感到偏执。 下面是 3.5 的实现方式:
下面是我们在 lambda 之前的时代的实现方式:
You have a design flaw. Also, don't be paranoid about data hiding. Here's 3.5's way to do it:
Here's how we'd do it in pre-lambda days:
最好的方法是:
当您有一些复杂的访问或继承限制,并且强制执行它需要代码过于复杂时,有时最好的方法就是对其进行正确的注释。
但请注意,如果此限制具有某些安全隐患,则您不能依赖于此,因为您依赖于将使用此代码的开发人员的善意。
The best way to do it would be:
When you have some complex access or inheritance restriction, and enforcing it demands too much complexity in the code, sometimes the best way to do it is just properly commenting it.
Note however that you cannot rely on this if this restriction has some security implications, as you are depending on the goodwill of the developer that will use this code.
您不能以这种方式执行此操作,但您可以从派生类访问属性的 setter 方法,因此您可以使用继承来达到此目的。 您所要做的就是放置protected访问修饰符。 如果您尝试这样做,您的同事是对的:)。 您可以尝试这样做:
请记住,属性的 set 方法只能从派生类访问。
You cannot do that on that way, but you can access a property's setter method from a derived class, so you can use inheritance for the purpose. All you have to do is to place protected access modifier. If you try to do so, your colleague is right :). You can try doing it like this:
keep in mind that the set method of the property is only accessible from the derived class.
或者,您可以将这两个类单独放在一个程序集中,并将 setter 作为内部类。 不过,我会投票赞成设计缺陷,除非 milot 之前的回答(继承和保护)有意义。
Or you could have these two classes in an assembly alone and have the setter as internal. I would vote up for the design flaw though, unless the previous answer by milot (inheriting and protected) makes sense.
您可以这样做:
这意味着您可以使用调用类中的“this”指针。 我会质疑你试图实现的逻辑,但在不了解情况的情况下,我无法提供任何进一步的建议。 我要说的是:如果可以重构代码以使其更清晰,那么这样做通常是值得的。
但这相当混乱,而且肯定不是万无一失的......您已被警告!
或者...
您可以将具有属性的类(A 类)的委托传递给管理器类(B 类)。 委托可以引用 A 中的私有函数,以允许 B 将该委托作为任何普通函数调用。 这排除了 A 知道 B 的可能性,并且有可能 A 是在 B 之前创建的。同样......混乱且并非万无一失!
You could do:
This would mean that you could use a 'this' pointer from the calling class. I would question the logic of what you're attempting to achieve, but without knowing the scenario I can't advise any futher. What I will say is this: if it is possible to refactor your code to make it clearer, then it is often worthwhile doing so.
But this is pretty messy and certinly NOT fool-proof ... you have been warned!
Alternativly...
You could pass a delegate from the Class with the Property (Class A) to the Manager Class (Class B). The delegate can refer to a private function within A to allow B to call that delegate as any normal function. This precludes that A knows about B and potentially that A is created before B. Again... messy and not fool-proof!
您可以通过在“可设置类”中创建一个公共属性来实现此目的,该属性将从具有受保护属性的真实类继承......这样,只有继承类可以设置,而不是不继承的类。 但缺点是你需要有一个继承类......
You can achieve to this by making a Public property in your "settable class" that will inherit from the real class that will have a protected property... this way only the inherit class can SET and not class that doesn't inherit. But the drawback is that you will require to have an inherit class...
反思,尽管我同意必须这样做只是为了绕过访问修饰符可能表明设计不好。
Reflection, though I would agree that having to do this just to get around an access modifier is probably an indication of a bad design.
这是一个设计缺陷,因为它似乎混淆了两个对象的范围。
类的属性应该可以在该类的上下文中访问,至少在内部是这样。
听起来您的项目类上的可设置属性实际上是管理器类的属性。
您可以通过紧密耦合这两个类来完成与您想要的类似的操作:
不幸的是,这也不是一个很好的设计。
The reason this is a design flaw is because it seems muddled between the scope of the two objects.
The properties of a class should be accessible in the context of that class, at least internally.
It sounds like the settable property on your item class is really a property of the manager class.
You could do something similar to what you want by closely coupling the two classes:
Unfortunately this isn't great design either.
您要寻找的是 C++ 所谓的 Friend 类,但 c# 或 vb 都没有此功能。 关于这种功能的优点存在很多争论,因为它几乎鼓励类之间非常强的耦合。 在 C# 中实现此功能的唯一方法是使用反射。
What your looking for is what C++ calls a Friend class but neither c# or vb has this functionality. There is a lot of debate as to the merit of such functionality since it almost encourages very strong coupling between classes. The only way you could implement this in c# would be with reflection.
如果您的目标是让
Foo
类的某些属性(例如Bar
,类型为Biz
)被其他对象更改,而无需公开暴露它,一个简单的方法是拥有一个Foo
实例,该实例应该可以被其他对象更改,以便向该其他对象传递Action
> 指向一个私有方法,该方法将Bar
更改为传入的值。 另一个对象可以使用该委托来更改提供它的对象的Bar
值。如果希望赋予某种类型
Woozle
的所有实例设置Foo
任何实例的Bar
值的能力,而不是公开此类基于每个实例的能力,人们可能要求Woozle
有一个公共静态方法Woozle.InstallFooBarSetter
,该方法采用Action类型的参数。
和Object
类型之一。 然后,Foo
应该有一个静态方法WoozleRequestBarSetter
,它接受一个Object
,并将其传递给Woozle.InstallFooBarSetter
以及一个Action
。Woozle
的类初始值设定项应生成一个新的Object
,并将其传递给Foo.RequestBarSetter
; 它将将该对象与委托一起传递给Woozle.InstallFooBarSetter
。 然后,Woozle 可以确认传入的对象是它生成的对象,如果是,则安装适当的委托。 以这种方式执行操作将确保除了Woozle
之外没有人可以获得委托(因为委托仅传递给Woozle.InstallFooBarSetter
),并且Woozle
可以确定它的委托来自Foo
(因为没有其他人可以访问Woozle
创建的对象,并且Woozle.InstallFooBarSetter
也不会没有它就做任何事情)。If your goal is to have a class
Foo
let some property (e.g.Bar
, of typeBiz
) to be changed by some other object, without exposing it publicly, a simple way to do that is to have an instance ofFoo
which is supposed to be changeable by some other object to pass that other object anAction<Biz>
which points to a private method that changesBar
to the passed-in value. The other object may use that delegate to change theBar
value of the object that supplied it.If one wishes to have give all instances of some type
Woozle
the ability to set theBar
value of any instance ofFoo
, rather than exposing such abilities on a per-instance basis, one may require thatWoozle
have a public static methodWoozle.InstallFooBarSetter
which takes a parameter of typeAction<Foo, Biz>
and one of typeObject
.Foo
should then have a static methodWoozleRequestBarSetter
which takes anObject
, and passes it toWoozle.InstallFooBarSetter
along with anAction<Foo,Biz>
. The class initializer forWoozle
should generate a newObject
, and pass it toFoo.RequestBarSetter
; that will pass the object toWoozle.InstallFooBarSetter
along with a delegate.Woozle
can then confirm that the passed-in object is the one that it generated, and--if so--install the appropriate delegate. Doing things this way will ensure that nobody butWoozle
can get the delegate (since the delegate is only passed toWoozle.InstallFooBarSetter
), andWoozle
can be sure its delegate comes fromFoo
(since nobody else would have access to the object thatWoozle
created, andWoozle.InstallFooBarSetter
won't do anything without it).如果这是一个设计缺陷取决于你想做什么。 您可以使用 System.Diagnostics 中的 StackTrace 类来获取设置属性的类的类型,然后与您想要允许设置属性的类型进行比较。但也许有更好的方法来执行类似的操作(例如装箱)
if it is a design flaw depends on what you want to do. You could use the StackTrace class from System.Diagnostics to get the Type of the class setting your property and then compare to the type you want to allow setting yor property..but maybe there are better ways for performing something like this (e.g. boxing)