一种类型如何访问另一种类型属性的私有资源库
本文关键字:类型 属性 资源库 另一种 何访问 一种 访问 | 更新日期: 2023-09-27 17:47:24
我所需要的只是一种方法,使一个类的属性只能从另一个类(一种管理器类("设置"。
这在 c# 中甚至可能吗?
我的同事"可靠地"告诉我,我有一个设计缺陷,但我觉得我至少应该在我承认失败之前问问社区!
不,在 C# 中以任何干净的方式执行此操作是不可能的。 你可能有一个设计缺陷;-(
您可以使用 internal
修饰符,它允许同一程序集中的所有类型访问数据(如果使用 [InternalsVisibleTo]
则访问指定的程序集 - 但不可以:C# 中没有等效friend
。
例如:
public string Foo {get; internal set;}
你有一个设计缺陷。 另外,不要对数据隐藏感到偏执。 这是 3.5 的方法:
class Program
{
static void Main(string[] args)
{
Managed m = new Managed();
Console.WriteLine(m.PrivateSetter);
m.Mgr.SetProperty("lol");
Console.WriteLine(m.PrivateSetter);
Console.Read();
}
}
public class Managed
{
private Manager _mgr;
public Manager Mgr
{
get { return _mgr ?? (_mgr = new Manager(s => PrivateSetter = s)); }
}
public string PrivateSetter { get; private set; }
public Managed()
{
PrivateSetter = "Unset";
}
}
public class Manager
{
private Action<string> _setPrivateProperty;
public Manager(Action<string> setter)
{
_setPrivateProperty = setter;
}
public void SetProperty(string value)
{
_setPrivateProperty(value);
}
}
以下是我们在 lambda 之前的做法:
public class Managed
{
private Manager _mgr;
public Manager Mgr
{
get { return _mgr ?? (_mgr = new Manager(this)); }
}
public string PrivateSetter { get; private set; }
public Managed()
{
PrivateSetter = "Unset";
}
public class Manager
{
public void SetProperty(string value)
{
m.PrivateSetter = value;
}
private Managed m;
public Manager(Managed man)
{
m = man;
}
}
}
最好的方法是:
/// <summary>
/// Gets or sets foo
/// <b>Setter should only be invoked by SomeClass</b>
/// </summary>
public Object Foo
{
get { return foo; }
set { foo = value; }
}
当您有一些复杂的访问或继承限制,并且强制执行它需要代码中的太多复杂性时,有时最好的方法是正确注释它。
但请注意,如果此限制具有一些安全隐患,则不能依赖此限制,因为您依赖于将使用此代码的开发人员的善意。
您不能以这种方式执行此操作,但您可以从派生类访问属性的 setter 方法,因此您可以使用继承来实现此目的。您所要做的就是放置受保护的访问修饰符。如果你尝试这样做,你的同事:)是对的。您可以尝试这样做:
public string Name
{
get{ return _name; }
protected set { _name = value; }
}
请记住,只能从派生类访问属性的 set 方法。
,您可以将这两个类单独放在一个程序集中,并将 setter 作为内部类。不过,我会投票支持设计缺陷,除非 milot 之前的答案(继承和保护(有意义。
你可以做:
public void setMyProperty(int value, Object caller)
{
if(caller is MyManagerClass)
{
MyProperty = value;
}
}
这意味着您可以使用调用类中的"this"指针。我会质疑你试图实现的目标的逻辑,但在不知道场景的情况下,我不能进一步建议。我要说的是:如果可以重构你的代码以使其更清晰,那么这样做通常是值得的。
但这非常混乱,而且绝对不是万无一失的......你已经被警告了!
交替...
可以将具有属性的类(类 A(中的委托传递到管理器类(类 B(。委托可以引用 A 中的私有函数,以允许 B 将该委托作为任何普通函数调用。这排除了 A 知道 B 并且可能 A 是在 B 之前创建的。凌乱且不万无一失!
在"可设置类"中创建一个 Public 属性来实现这一点,该属性将从具有受保护属性的真实类继承......这样,只有继承类可以 SET,而不可以设置不继承的类。但缺点是你需要有一个继承类......
反射,尽管我同意必须这样做只是为了绕过访问修饰符可能表明设计不佳。
public class Widget
{
private int count;
public int Count
{
get { return this.count; }
private set { this.count = value; }
}
}
public static class WidgetManager
{
public static void CatastrophicErrorResetWidgetCount( Widget widget )
{
Type type = widget.GetType();
PropertyInfo info = type.GetProperty("Count",BindingFlags.Instance|BindingFlags.NonPublic);
info.SetValue(widget,0,null);
}
}
这是一个设计缺陷的原因是因为它似乎在两个对象的范围之间混淆了。
类的属性应该可以在该类的上下文中访问,至少在内部是这样。
听起来项目类上的可设置属性实际上是管理器类的属性。
您可以通过紧密耦合这两个类来执行类似于您想要的操作:
public class MyItem {
internal MyItemManager manager { get;set; }
public string Property1 {
get { return manager.GetPropertyForItem( this ); }
}
}
不幸的是,这也不是很好的设计。
>你要找的是C++所说的朋友类,但 c# 或 vb 都没有此功能。 关于这种功能的优点有很多争论,因为它几乎鼓励类之间的非常强的耦合。在 c# 中实现这一点的唯一方法是使用反射。
如果你的目标是拥有一个类Foo
让一些属性(例如 Bar
,类型 Biz
( 要由其他对象更改,而不公开它,一个简单的方法是有一个 Foo
的实例,该实例应该可以被其他对象更改,以向该其他对象传递一个Action<Biz>
,该指向Bar
更改为传入值的私有方法。 另一个对象可以使用该委托来更改提供它的对象的Bar
值。
如果希望让某种类型的所有实例Woozle
能够设置任何Foo
实例的Bar
值,而不是在每个实例的基础上公开这种能力,则可以要求Woozle
有一个公共静态方法Woozle.InstallFooBarSetter
该方法采用类型为 Action<Foo, Biz>
和类型为 Object
的参数。 然后Foo
应该有一个静态方法WoozleRequestBarSetter
它接受一个Object
,并将其与Action<Foo,Biz>
一起传递给Woozle.InstallFooBarSetter
。 Woozle
的类初始值设定项应该生成一个新的Object
,并将其传递给Foo.RequestBarSetter
;这会将对象与委托一起传递给Woozle.InstallFooBarSetter
。 然后,Woozle
可以确认传入的对象是它生成的对象,如果是,则可以安装相应的委托。 以这种方式做事将确保除了Woozle
之外没有人可以获取委托(因为委托只传递给Woozle.InstallFooBarSetter
(,并且Woozle
可以确定其委托来自Foo
(因为没有其他人可以访问Woozle
创建的对象,没有它Woozle.InstallFooBarSetter
不会做任何事情(。
是设计缺陷取决于你想做什么。您可以使用 System.Diagnostics 中的 StackTrace 类来获取设置属性的类的类型,然后与要允许设置 yor 属性的类型进行比较。但也许有更好的方法来执行这样的事情(例如拳击(