首页新闻找找看学习计划

如何让一个类的方法的仅对特定的类可见

0
悬赏园豆:20 [已解决问题] 解决于 2016-09-28 00:52

C#中,如类B有方法HelloB(), 我想类HelloB()只能在类A中被实例化调用,在其他类中不能被调用,如何实现?

烦请大神指点,在此谢过!

C#
HNLY的主页 HNLY | 初学一级 | 园豆:101
提问于:2016-09-26 00:07
< >
分享
最佳答案
1

方法倒有一个。不知道你用过内部类没有?可以用这个实现。

public class C

{

private class A{}

private class B{}

public A CreatA(){return new A();}

public B CreatB(){return new B{};}

}

这是最简单的例子,实际用时可能还要加上单例或工厂。但是应该可以满足你的需求。

收获园豆:20
中文代码 | 小虾三级 |园豆:951 | 2016-09-27 17:42

@中文代码, 非常感谢你提供的代码,这个是对我上面描述的“网页分析类”的定义。 不过,貌似不能实现A和B 只能 让C 访问。

HNLY | 园豆:101 (初学一级) | 2016-09-27 17:48

@HNLY: 你可以b继承a;c继承b;这样你就可以用 c.b.a这样调用

小粽子饱饱 | 园豆:251 (菜鸟二级) | 2016-09-27 18:02

@HNLY: 试一下就知道了。A、B是不能在外部使用的,它是一个私有内部类。你只能以C的实例对象调用它。所以,除C以外,其它任何对象都不能访问A、B的。

当然,如果你用成员公开A、B,那就不行了。那样也违反了开-闭原则。

中文代码 | 园豆:951 (小虾三级) | 2016-09-27 18:20

@小粽子饱饱: 让B继承A, 这个确实是个解决办法,不过,实际上B和A是完全不相干的类,继承的话容易引起混乱。

HNLY | 园豆:101 (初学一级) | 2016-09-27 23:56
其他回答(9)
0

没遇到过,你的需求目的是?

 

~扎克伯格 | 园豆:1799 (小虾三级) | 2016-09-26 09:09

我想定义两个类,这个两个类分别完成不同的工作,比如分别解析不同的网站内容,做不同的处理,然后再创建一个新的类,把这两个类的方法集中起来假设叫做 网页分析 类。其中,两个类的方法完全没有关联,完全独立。

我是不想把所有的方法都柔和到一个类里面。分割到各个子类里面好单独分析。

所以,那两个具体实现的类中的方法我想隐藏起来,仅对新的 “网页分析 类”可见, 不知道设计是否合理,或者有其他更好的办法。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 12:16
0

这个比较你可以采用将HelloB方法放在private中,然后对类A设置友元,即friend,这样A就可以访问B的私有成员。欢迎采纳,谢谢。

Boblim | 园豆:492 (菜鸟二级) | 2016-09-26 09:16

好像C#里面没有对方法的友元,只有 InternalsVisibleTo 是对 程序集的设置。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 11:32

@HNLY: C#里没有友元,那你可以通过传递一个参数来限制。例如:

public  class A
{
   public void Mothed(B b)
   {
      
   }
}

支持(0) 反对(0) Boblim | 园豆:492 (菜鸟二级) | 2016-09-26 13:20

@Boblim: 貌似这个方法不太好。两个子类A和B, 网页分析类为C, 我同样可以在类D中创建方法,并传入类C的实例,这样就让代码显得更有些乱了。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 19:08
0

怎么会有这种需求?

顾晓北 | 园豆:9520 (大侠五级) | 2016-09-26 09:33

我想定义两个类,这个两个类分别完成不同的工作,比如分别解析不同的网站内容,做不同的处理,然后再创建一个新的类,把这两个类的方法集中起来假设叫做 网页分析 类。其中,两个类的方法完全没有关联,完全独立。

我是不想把所有的方法都柔和到一个类里面。分割到各个子类里面好单独分析。

所以,那两个具体实现的类中的方法我想隐藏起来,仅对新的 “网页分析 类”可见, 不知道设计是否合理,或者有其他更好的办法。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 12:17

@HNLY: 你这应该这样:新建一个类,是父类,然后有一个虚方法,其他两个类继承自这个类,然后实现这个类的虚方法(或者抽象方法)

支持(0) 反对(0) 顾晓北 | 园豆:9520 (大侠五级) | 2016-09-26 13:18

@顾晓北: 那这样的两个类实现的方法还是Public的吧,还是可以被其他类访问到。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 19:04

@HNLY: 根据你的描述,没明白你为什么要纠结public,private的问题。。。

支持(0) 反对(0) 顾晓北 | 园豆:9520 (大侠五级) | 2016-09-27 09:21
0

把A、B放在一个命名空间,HelloB设置为受保护的,然后该命名空间不要放其他类,能勉强达到。。

幻天芒 | 园豆:36522 (高人七级) | 2016-09-26 09:37

谢谢@幻天芒, 如果分到其他类库,我就可以用 InternalsVisibleTo 设置,但是这个貌似有些麻烦,我不太想这么做, 根据我上面回复的需求,你有其他更好的设计吗?

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 12:20

@HNLY: 暂时想不到更好的实现方式了~

支持(0) 反对(0) 幻天芒 | 园豆:36522 (高人七级) | 2016-09-26 14:52
0

友元是对的

吴瑞祥 | 园豆:28731 (高人七级) | 2016-09-26 09:39

好像C#里面没有对方法的友元,只有 InternalsVisibleTo 是对 程序集的设置。

https://msdn.microsoft.com/zh-cn/library/mt632254.aspx

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 11:32
1

对每一个函数做一个接口

然后写一个实现它的类A  你想让B类能访问哪些函数你就让A类实现哪些接口
如果还有一个类C需要A类的函数  也需要另外一些函数  那么就讲C类继承A类并且实现接口就好了

叶帅辉 | 园豆:266 (菜鸟二级) | 2016-09-26 17:12

@叶帅辉, 用接口确实是个好的设计,不过,这样如何能限制A仅能被B类访问呢? 因为类A实现类接口,如果想被B访问,肯定是Public的,那同样是对其他类可见的。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 19:13

@HNLY: 你可以写一个A类的构造函数  传一个参数 就是调用的对象的类型然后在构造函数里面进行限制  如果不是指定的类型可以直接返回一个指定的错误并且A类的子类都显式继承这个构造函数;

虽然不能做到编译时报错,但是运行时报错应该也能达到楼主的要求吧?

注: 可以写两个类  分别表示可以访问A类,不能访问A类的 然后调用A类的这个类继承可以调用A类的类或者不能调用A类的类   只要判断这个派生类是否属于父类就好了

支持(1) 反对(0) 叶帅辉 | 园豆:266 (菜鸟二级) | 2016-09-26 19:36

@叶帅辉: 非常感谢你详细的回答。 你的方法好像跟上面@Boblim的建议一样吧?貌似,我的需求没有太好的办法直接实现了,我随后尝试下你们的建议。谢谢啦!

另外,在项目中,类似的这种需求是不是常见的都是封装到类库里面了,然后引用类库来实现代码隐藏或类似我的需求?如,把子类封装到DAL或者BLL中?

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-26 23:30

@HNLY:具体如何封装需要看你的这个需求是什么需求如果你这个是为了实现特定的业务还是放在bll吧,如果是作为一个工具可以单独写一个类库,这种东西基本不会放在dal里面;

我说的传参方法可以直接传this

调用的类都显示继承一个类 ParentObject

然后再构造函数

1 public A(ParentObject o){
2 if(!(o is B)){
3 Console.Write("当前类型无法创建对象");}
4 }
View Code

 

你在调用构造函数的时候传this就可以了

代码我就在网页上写的  可能有些不对的地方  你自己改下

支持(1) 反对(0) 叶帅辉 | 园豆:266 (菜鸟二级) | 2016-09-26 23:45

@叶帅辉,我根据你的描述写了如下代码,你看下是否是这个意思,如果有不对的,烦请帮忙修改下。非常感谢亲耐心细致的回复。

        static void Main(string[] args)
        {
            A _a = new A();
            _a.CallHelloB();

            C _c = new C();
            _a.CallHelloB();
        }
    }

    public class A: ParentObject
    {
        public void CallHelloB()
        {
            B _b = new B (this);
            _b.HelloB();
            Console.WriteLine("End CallHelloB From Class A");
        }
    }

    public class B: ParentObject
    {
        public B(ParentObject o)
        {
            if (!(o is A))
            {
                Console.Write("Wrong Caller");
            }
        }
        public void HelloB()
        {
            Console.WriteLine("Hello B");
        }
    }

    public class C
    {
        public void CallHelloB()
        {
            B _b = new B(new A());
            _b.HelloB();
            Console.WriteLine("End CallHelloB From Class C");
        }
    }

    public class ParentObject { }
支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-27 18:03

@HNLY: 

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            B _b = new B();
            _b.Test();
            Console.Read();
            try
            {

                C _c = new C();
                _c.Test();
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Console.ReadLine();
            Console.ReadLine();
        }
    }

    public class ParentObject { }
    interface ICallHelloB
    {
        void CallHelloB();
    }
    /// <summary>
    /// 实现ICallHelloB接口 并且只有一个带参数的构造函数
    /// </summary>
    public class A : ICallHelloB
    {
        /// <summary>
        /// 传入当前对象this
        /// 程序自动判断当前类型能否创建对象
        /// </summary>
        /// <param name="o">传入this</param>
        public A(object o)
        {
            //表示只接受ParentObject类或其派生类的对象
            if (!(o is ParentObject))
            {
                throw new Exception("Wrong Caller");
            }
        }

        public void CallHelloB()
        {
            Console.WriteLine("End CallHelloB From Class A");
        }
    }
    /// <summary>
    /// 这个类继承ParentObject实现可实例化A类以及调用它的函数
    /// </summary>
    public class B: ParentObject
    {
        public void Test()
        {
            A _a = new A(this);
            _a.CallHelloB();
        }
    }
    /// <summary>
    /// 该类不继承ParentObject类所以无法实例化A类并抛出异常
    /// </summary>
    public class C
    {
        public void Test()
        {
            A _a = new A(this);//这里运行时抛出异常
        }
    }
}

我自己在你写的基础上改了一下;有背景色的是实现这个的基础;

如果不知道需要继承ParentObject类那么就不会被实例化出来

支持(1) 反对(0) 叶帅辉 | 园豆:266 (菜鸟二级) | 2016-09-27 20:23

@叶帅辉: 这个方法确实不错,谢谢亲的代码啦。这边有个风险,如我下面代码所示,仍然还是无法完全限制。不过,还是十分感谢亲的建议,这个方法也是可行的,只是要严格根据约定,必须传入this 才行。可能理解有误,望指点。

我参照@中文代码 的建议,让A和B 都变成C 的私有内部类就行了,这个问题我确实是没考虑过。详细情况我最下面的回复。 

    public class C
    {
        public void Test()
        {
            A _a = new A(new ParentObject());
        }
    }
支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-28 00:47

@叶帅辉: 实在不好意思了,我原本想把园豆拆出给你点的,貌似结贴时候没办法这样子,实在抱歉亲。再次感谢亲的指点和详细的回答,不好意思啦。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-28 00:55

@HNLY: 这个的确是问题的  但是可以讲有背景色的部分封装成一个独立的dll以供调用 除非告知使用者该继承哪个类  否则不太容易知道具体用哪个类吧?

支持(1) 反对(0) 叶帅辉 | 园豆:266 (菜鸟二级) | 2016-09-28 00:59

@HNLY: 没事

支持(0) 反对(0) 叶帅辉 | 园豆:266 (菜鸟二级) | 2016-09-28 00:59

@叶帅辉: 嗯,对的,确实是这样。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-28 15:24
0

定义类的时候用protected   只有继承这个类的其他类才能调用

小粽子饱饱 | 园豆:251 (菜鸟二级) | 2016-09-27 15:44

说错,是类中方法用protected修饰,其他类要调用必须继承 这个类

支持(0) 反对(0) 小粽子饱饱 | 园豆:251 (菜鸟二级) | 2016-09-27 15:47

@小粽子饱饱: Proctected 倒是能部分实现,但是如果C 想同时 调用 A和B 的实现,就无法同时继承自A和B 了。

支持(0) 反对(0) HNLY | 园豆:101 (初学一级) | 2016-09-27 17:49
0

@中文代码: A和B 是C的内部私有类这个问题我倒是没有想过,好像确实也是这样子,毕竟只能C来访问A和B。 

按照这个思路来,创建两个不同的文件名,但是内容都是partial class C, 里面分别定义A和B的内容,然后再创建一个C的文件夹,里面写入调用A和B的内容。这样子,就从外观来看是创建了子类A和B。(由于无法上传照片,不知是否描述清楚。)

备注:由于我想把最终我的做法单独拿出来,所以点击了“自己解决”,不知是否有什么影响,还请以上各位见谅。在此,感谢各位这几天的关注和帮助,谢谢你们给我的各种想法和建议,以后还请多多指教,谢谢啦!

HNLY | 园豆:101 (初学一级) | 2016-09-28 00:39
0

命名空间 + 一个类的描述符 可以做到  忘记什么了

小尧弟 | 园豆:500 (菜鸟二级) | 2017-03-02 14:01

A B 在同一个命名空间namespace1中,A可以生成B()的实例,不在 namespace1 中的C没发访问B()

支持(0) 反对(0) 小尧弟 | 园豆:500 (菜鸟二级) | 2017-03-02 14:04
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册