【问题标题】: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";

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

【问题讨论】:

    标签: c# class struct interface access-modifiers


    【解决方案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);
                    }
                }
            }
        }
    

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

    【讨论】:

      猜你喜欢
      • 2017-08-17
      • 1970-01-01
      • 2013-09-27
      • 2011-04-21
      • 2010-11-26
      • 2014-01-27
      • 2014-04-06
      • 2021-06-10
      相关资源
      最近更新 更多