【问题标题】:Access Modifier, Inheritance and Foreign Assembly访问修饰符、继承和外部程序集
【发布时间】:2011-04-21 20:49:22
【问题描述】:

假设我在 myFramework 命名空间中有一个基类:

using System;
using System.Collections.Generic;
using System.Text;

namespace myFramework
{
    public class baseClass
    {
        internal int m_value;

        internal int getValue() {
            return m_value;
        }

        internal void setValue(int value) {
            m_value = value;
        }

    }
}

在 MyApplication 命名空间中我继承自它:

using System;
using System.Collections.Generic;
using System.Text;
using myFramework;

namespace MyApplication
{
    class InheritedClass: baseClass
    {
    }
}

在 MyApplication 命名空间中的一个表单中我使用它:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using myFramework;

namespace MyApplication
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            InheritedClass inheritedClass = new InheritedClass();

            inheritedClass.setValue(10);
            textBox1.Text = inheritedClass.m_value.ToString();
        }
    }
}

如您所见,我已使用 internal 修饰符声明 m_value,以便我可以从 Form 访问它。

现在如果我在单独的程序集中编译 myFramework 会怎样?内部不会再工作了?那么我可以使用任何修饰符吗?受保护的甚至不能少做这项工作。我有义务使用 public 吗?

是否有一个访问修饰符允许拥有一个类(inheritedclass)的对象(表单)访问他拥有的所有类和父类的所有成员,就像 internal 一样,除了 internal 不考虑所有权但是在哪里类已声明?

更新:当然在实际使用中,我的基类与表单(或视图)有严格的语义,所以由我决定是否应该这样做,我的问题不是我是否应该这样做,我的问题是是否有可能或者如果我将不得不使用诸如按合同设计之类的东西,我觉得为这些基本要求添加另一个工具很愚蠢。

【问题讨论】:

    标签: c#


    【解决方案1】:

    表单不“拥有”类,可以说表单“拥有”该类的一个实例,但即使这样也很不清楚;通常我们使用“自己的”来表示“对”负有最终责任,在某些情况下必须处置或以其他方式“清理”对象。

    表单与baseClass的内部工作完全无关。如果表单需要访问 baseClass 的成员,它应该是公共的。或者,如果 baseClass 的成员应该是私有的、内部的、受保护的或受保护的内部的,那么表单就没有业务处理它。

    如果您希望将不相关的类访问权授予故意非公共成员,则说明您的设计出了问题。

    【讨论】:

    • 在 UML 语义中,所有权是有一定意义的。至于“如果表单需要访问baseClass的成员,它应该是公共的。”不正是因为我不希望不是类型形式的类访问这个基类。再一次,语法不应该掩盖语义需求。这并不是因为一种语言不允许表达现实世界的语义,它是正确的。这只是过去的继承和缺乏进化。
    • 所以确定如果我这样做是在我的基类显然与表单无关的情况下,如果这个基类将例如实现一些我将创建的接口仅用于我将丰富的表单用我自己的语义。
    • 如果 form 与 baseClass 有某种特殊的双向关系,就像在其他语言中使用 friend 关键字那样,那么我们能做的最好的事情就是使用 InternalsVisibleTo 属性,但是唉这也使它们对表单所在的程序集的其余部分可见。如果 baseClass 实现了仅由表单使用的接口,那么您可以将该方法放在其中一个接口中。不过,从这个例子中,没有什么可以看出 form 与使用 baseClass 的任何其他类不同。
    【解决方案2】:

    “所有权”在这里没有任何意义,这些是完全不相关的类。充其量你可以跳过InternalsVisibleTo attribute 箍。

    【讨论】:

    • 感谢这个属性很有趣,但是对于未知的未来客户应该可以看到的框架,我看不到如何使用它?
    • 也许有办法在运行时注册这样的客户端?
    • 可访问性是一个编译时特性。使用反射来解决它是一个非常丑陋的黑客。
    【解决方案3】:

    根据所示示例,公共属性将完全满足您的需求。但是,如果您想隐藏该成员(并且您提前确切知道哪些程序集需要访问它),InternalsVisibleToAttribute 就可以解决问题。

    我在不想暴露某个属性但我需要访问它以进行测试的情况下使用它。在这种情况下,我确切地知道我只希望我的测试程序集能够访问该属性并且我可以控制它的使用方式。

    【讨论】:

    • InternalsVisibleToAttribute 会很好,只是我的基类将在一个框架中,该框架事先不知道哪个程序集将是客户端。也许有办法在运行时注册这样的客户端?
    • 我不知道这样做的方法。该属性应用于 assembly.cs 文件,因此必须在编译时设置。听起来公共财产是您想要的方式;你有什么理由犹豫不决吗?属性旨在提供对引用类实例的事物的访问权限,这正是您所拥有的。
    猜你喜欢
    • 2016-01-29
    • 2017-08-17
    • 1970-01-01
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-26
    • 2014-01-27
    相关资源
    最近更新 更多