访问修饰符和继承

Posted

技术标签:

【中文标题】访问修饰符和继承【英文标题】:Access modifiers and inheritance 【发布时间】:2016-01-29 01:47:25 【问题描述】:

我试图让一个类只允许在命名空间范围内使用new 关键字进行初始化。虽然我需要能够使用它的 type 示例

namespace MyNameSpace 

   class MyClass 

      public string Name  get; set; 
   

   class NewMyClass 
       MyClass cls = new MyClass();
       cls.Name = "My Name";
    
 

但在Program.cs 上,我只希望用户能够执行以下操作。

NewMyClass myC = new NewMyClass();
List<MyClass> myList = myC.method();

foreach(MyClass a in myList)
    Console.WriteLine(a.property);
 

正如您所希望看到的,我想让他们将其用作数据类型,因为它将是它需要的列表类型。但我不希望用户在MyClass 中设置Name,也不能调用new MyClass。我已经尝试将MyClass 制作成一个接口,但我需要创建新实例来存储在List 中。

我也尝试设置 private set 以便只有 NewMyClass 可以设置它们,但这也不起作用。我已经读了一段时间了,我就是这么卡住了!

我希望用户能够做什么~!

List<MyClass> //use as a datatype
Console.WriteLine(a.property); //call the property from the list

我不希望用户做的事情!

new MyClass();
a.property = "Other Name" //set the value.

原因

用户没有理由调用MyClass,只有NewMyClass 应该调用它。用户也没有理由将值分配给MyClass 中的任何属性。我正在使用一个类,因为我被告知不要使用struct,这没关系,因为到目前为止我喜欢类方法的多功能性。但是我需要对用户进行很多限制。

如果我在这方面做错了,请告诉我,我对 C# 很陌生,所以请不要害怕告诉我你会走哪条路以及为什么这样我可以理解你的推理。

思考的第二步

回到结构体方法。我现在有

internal struct MyClass 
    public string Name get; set;

我喜欢这样做的原因是当我这样做时

MyClass cls = new MyClass();

它给出一个警告,表明 cls 已分配但从未使用过。但是当我们这样做时

cls.Name = "google";

那个警告消失了,我不想让用户设置,但只有我的主类可以这样做。

【问题讨论】:

【参考方案1】:

您需要公开“MyClass”,但它是“内部”成员。当然,“内部”仅在这些类位于单独的程序集中时才有效。

namespace MyNameSpace 

   public class MyClass 

       internal string Name  get; set; 
   

   public class NewMyClass 
       MyClass cls = new MyClass();
       cls.Name = "My Name";
    
 

【讨论】:

做了你所拥有的,(回到课堂),如果调用MyClass cls = new MyClass()Program.cs中的用户仍然可以访问这些成员 @EasyBB,您需要将它们放在单独的项目程序集(DLL)中 他们两个像你一样吗? @EasyBB,是的,将两者放在单独的程序集中。否则NewMyClass 将无法访问internals 的MyClass 好的,我试试看。【参考方案2】:

您不能通过namespace 限制访问。最接近您要查找的访问修饰符是internal,它将范围限制为给定程序集。

如果您将MyClassNewMyClass 放在同一个程序集中,并且将MyClass 构造函数的访问修饰符设置为internal,您就可以找到解决方案。

参考:https://msdn.microsoft.com/en-us/library/wxh6fsc7.aspx

【讨论】:

这会破坏将其用作数据类型的目的吗?【参考方案3】:

虽然很难将创建限制为仅一种不在继承链中的类型(由于缺少您需要的 if accessibility level),但您可以使用嵌套类型进行技巧。

class NewMyClass 

  private static Func<MyClass> create = null;

  public class MyClass 
    public static void Init()  NewMyClass.create = ()=> new MyClass();
    private MyClass() 
    public string Name  get; set; 
  

  public MyClass Method()
    MyClass.Init(); 
    MyClass cls = create();
    cls.Name = "My Name";
    return cls;
  
 

MyClassprivate 构造函数可防止任何人直接创建。

静态助手MyClass.Init() 让其外部类初始化私有委托以创建实例。嵌套类可以设置外部类的私有委托 - 所以两者必须合作才能提供您想要的保护。

请注意,更合理的方法是将MyClass 设为抽象(或接口)并在NewMyClass 中提供private 实现——您可能会发现这种方法也更容易测试。

【讨论】:

是的,我真的很新,所以抽象和界面对我来说都是新的。在使用接口时,编译器会出错,说你不能在接口上调用 new。我需要有 MyClass 的新实例,因为在 List 中会有 100 个实例,它们应该是唯一的。【参考方案4】:

如果您可以像 Glenn 已经指出的那样将它分成单独的程序集,那将是最好的。 然后你需要一个接口和一个工厂方法。

我还尝试更改您的程序,使其使用接口 -

    namespace MyNameSpace 



       public interface IMyClass
        
            string Name  get; 
        

       internal class MyClass : IMyClass  

          public string Name  get; internal set; 
       

       class NewMyClass 


           private IMyClass Init(string name)
           
               MyClass cls = new MyClass();
               cls.Name = name;
               return cls;
           

         public List<IMyClass> method()
           
              var collection = new List<IMyClass>();

              collection.Add(Init("1st Sample"));
              collection.Add(Init("2nd Sample"));

              return collection;
           

        
    

    namespace UserNameSpace
    

        public class Prog
        
            public static void Func()
            

                NewMyClass myC = new NewMyClass();
                List<IMyClass> myList = myC.method();

                foreach (IMyClass a in myList)
                
                    Console.WriteLine(a.Name);
                
            
        
    

但是,如果两个命名空间都在同一个程序集中,则用户无论如何都可以实例化该类。

【讨论】:

以上是关于访问修饰符和继承的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中的访问修饰符和包

修饰符和多态

继承中构造函数的默认访问修饰符

Swift 3:公共访问修饰符和内部访问修饰符之间的区别? [复制]

typescript 访问修饰符和 javascript 访问修饰符有啥区别?在使用打字稿时我应该更喜欢哪一个?

Java基础知识回顾之二 ----- 修饰符和String