【问题标题】:Is it possible to customize access modifiers behaviour?是否可以自定义访问修饰符行为?
【发布时间】:2011-12-30 12:58:40
【问题描述】:

我有一个由两个程序集组成的 winform 应用程序:一个业务层和一个前端层。每个用户控件(前端层)都与业务层的一个类相关,即 CustomerUserControl 使用 Customer 类。

可编辑属性,即 Customer.Name,具有公共设置器,因此可以通过前端控件修改其值。

我的问题是:是否可以更改属性的 setter 可访问性,使其或多或少地限制特定类。在我的示例中,Customer.Name 设置器将是内部的,前端控件无法访问,但其对应的控件 CustomerUserControl 可以访问。否则,setter 将是公共的,但不能被 CustomerUserControl 以外的控件访问。

是否可以实现这样的自定义访问权限?

【问题讨论】:

  • 您是否考虑过不可变或可冻结的结构?
  • 请不要在标题前加上“C#”。我们在Stack Overflow 上使用标签。
  • @asawyer:你是说传递一个元组吗?
  • @jolySoft 我想也许一个不可变的样式对象可以完全回避这个问题。
  • @Anne-Christine:你为什么不接受一个答案,奥利弗的最完整?

标签: c# .net access-modifiers


【解决方案1】:

我会为 setter 使用 internal 修饰符。这使得它只能在程序集中访问。如果 CustomerUserControl 在另一个程序集中,那么您可以使用 InternalsVisibleToAttribute

[assembly: InternalsVisibleTo("assembly name")] 

编辑:你是对的。这是另一种可能性: 声明一个接口,该接口将由允许设置名称的控件实现:

public interface ICustomerNameProvider
{
    string CustomerName { get; }
}

在客户中添加一个方法:

public void SetName(ICustomerNameProvider customerNameProvider)
{
    this.Name = customerNameProvider.CustomerName;
}

CustomerUserControl 会这样称呼它:

cust.SetName(this);

当然,这并不是万无一失的,但意外通过错误的控制是不可能的。

【讨论】:

  • 从问题来看,有两个程序集:业务和UI,所有的UserControl都在UI程序集中。这不会阻止 ProductUserControl 访问 Customer.Name 的设置器
  • +1,编辑后的答案比我发布的内容提高了设计质量。只需确保将接口放在第三个单独的程序集中,以避免循环引用。
【解决方案2】:

据我所知,没有办法将您要求的内容直接应用于属性设置器,因为它不知道调用从何处发起。但是,您可以使用 mutator 方法拼凑一些东西:

public class Customer
{
   ...
   public string Name
   {
      get;
      private set;
   }

   public void SetName(string callingControlName, string newName)
   {
      // you'd use TypeOf the same way to pass in callingControlName
      if(TypeOf(this).Name + "UserControl" == callingControlName)
         this.Name = newName;
   }
   ...
}

请注意,这是可笑的紧密耦合和糟糕的设计实践,但只要您严格遵守问题中概述的命名约定(CustomerCustomerUserControl 匹配 1:1),它应该可以满足您的需求。顺便说一句,我不只是将callingControlName"CustomerUserControl" 进行静态比较,以便稍微提高可维护性,以防您想做重命名CustomerUserControl 类之类的事情。同样需要注意的是,通过调用Customer.SetName("CustomerUserControl","badName") 很容易取消这一点。希望您不会将其暴露给会做类似事情的编码人员,但这是完全有可能的。

这里真正的问题是您的业务层不应该依赖于您的表示层。为什么需要限制对特定 UserControl 的设置访问?如果您确实需要(我想不出一个)业务属性的 set 只能从某个 UI 类访问,那么需要对您的应用程序进行一些重大的重新设计。

【讨论】:

  • ProductUserControl 仍然可以伪装成 CustomerUserControl。 SetName(new CustomerUserControl(),”newName”)
  • @Olivier Jacot-Descombes - 是的,可以,我在回答中明确提到了这一点。你错过了吗?
  • @EsotericScreenName:对不起,我专注于代码。请参阅我的答案的编辑。这里的业务层不中继 UI 层。 ICustomerNameProvider 将在业务层程序集或合同程序集中声明。
【解决方案3】:

您可以像这样限制 get 或 set 访问器的范围:

//private set accessor - this is what you're looking for
public int SomeProperty { get; private set; } 

//private get accessor
public int SomeOtherProperty { private get; set; }

【讨论】:

  • 这如何阻止另一个控件设置的值?
  • 因为我对你投了反对票而对我投了反对票,这违反了本网站的原则。你错过了我回答中的private set 部分吗?
  • 如何获得其中的价值?公共设置 SomeOtherProperty 的目的是什么?这两个属性有什么关系?
  • 第一个有一个private set 访问器,第二个有一个private get 访问器。它旨在表明您可以控制对属性的 get 和 set 访问器的访问。我首先包含了private set,因为这正是 OP 所要求的。
  • 问题是值是否可以由一个类和一个类设置。 UI 和业务对象之间的一对一映射。这就是我投票给你的方式,因为你没有回答这个问题。无论如何,正如我所说,感谢您的宝贵时间。
猜你喜欢
  • 2016-06-08
  • 1970-01-01
  • 2021-11-21
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 2016-01-28
  • 2014-11-03
  • 1970-01-01
相关资源
最近更新 更多