【问题标题】:Can `internal` access modifier be used to split a class over multiple files?可以使用“内部”访问修饰符将一个类拆分为多个文件吗?
【发布时间】:2016-06-30 11:30:23
【问题描述】:

我目前的主题是代码共享。建议使用访问修饰符internal 在多个文件之间共享代码是可能的。但是是吗?还是我弄错了?我无法发布链接,因为并非所有人都可以访问源代码。

是否可以在一个文件中定义类(如接口或抽象类)并在另一个文件中实现它(并在此处使用internal)?

这是一些伪代码(显然不起作用)。定义在一个文件中:

internal static class SongLoader
{
    internal async static Task<IEnumerable<Song>> Load();
    internal async static Task<Stream> OpenData();
}

在另一个文件中实现:

internal static class SongLoader
{
    internal const string Filename = "songs.json";

    internal static async Task<IEnumerable<Song>> Load()
    {
        // implementation
    }

    internal static Stream OpenData()
    {
        // implemenation
    }
}

或者是否可以在一个文件中定义Load(),在另一个文件中定义OpenData(),同时使用internal 访问修饰符?这可能吗?怎么样?

【问题讨论】:

  • 在同一程序集中的文件中:msdn.microsoft.com/en-us/library/7c5ka91b.aspx
  • @Stanley:是的,它应该在同一个程序集中,因为它被编译到同一个项目中(参见Shared Projects)。
  • internal 只是一个可见性修饰符。它与将一个类拆分为多个文件无关。其关键字是partial。但是没有你所描述的“类的定义”这样的东西。最接近的是“部分方法”,但它们必须返回 void 并且它们始终是私有方法。
  • @Dennis_E:我提到的网站上说 partial 是类镜像的一种变体(使用internal ...我也相信在我的示例中,只有 partial 是可能的。

标签: c# access-modifiers code-sharing


【解决方案1】:

internal 是一个访问修饰符,用于处理哪些代码可以访问您的函数。如果您想将一个类分解为同一命名空间内的多个文件,您正在寻找的是 partial 关键字。

https://msdn.microsoft.com/en-us/library/wa80x488.aspx

partial 不会让你定义相同的函数定义两次;如果这是您的目标,您将需要覆盖或虚拟化,或者使用基类。 Partial 有时很方便,但如果您不确定在哪里可以找到哪个类,它可能会导致解决方案有些混乱。

【讨论】:

  • 你也不能用部分类定义相同的函数两次,我认为这是 OP 想要的
  • 你说得对,如果他要查找相同的函数定义两次,那是行不通的。如果那是您正在寻找的路线,您必须覆盖基本功能。为了安全起见,我已将该评论添加到我的答案中。
【解决方案2】:

internal 说明符用于限制在包含程序集以外的类/成员。

代码共享是通过partial 类实现的。您可以参加课程 在一个文件中,另一部分在另一个文件中。

在文件 A 中

public partial class MyClass
{
  public void Foo()
  {
  }
}

在文件 B 中

public partial class MyClass
{
  public void Bar()
  {
  }
}

您不能像在 C++ 中那样在一个文件中声明并在一个文件中定义定义。 如果你有这样的要求,你应该考虑interfaceabstract 类。

【讨论】:

  • 在我的情况下,在不同程序集之间隐藏一个成员会很有帮助。所以我可以有不同的实现,但也可以使用相同的“合同”。关于声明和定义的拆分:这只是一个如何以某种方式实现代码共享的示例。在我的具体示例中,Foo() 正在调用 Bar(),但 Bar() 有不同的变体,具体取决于程序集。
  • 您基本上不能为不同的程序集专门实现相同的功能。如果您详细说明您遇到的问题,那么我们可以讨论替代解决方案。
  • 我想获得一些关于代码共享选项的知识。 internal 被提及为选项之一(partial 除外)。所以internal 似乎对代码共享没有帮助。现在我尝试按照您的建议使用partial,但我看不到这里的全部好处。如果您有兴趣,可以查看我的尝试here
  • 您已在部分类中将OpenData() 标记为virtual,并且您正尝试在部分类的其他部分中定义OpenData()。事实上,在编译时,所有成员都将在同一个类中,而不管文件如何。所以现在有两种名称和签名不明确的方法。而且您还从静态方法Load() 调用非静态方法OpenData()。如果你想要OpenData() 的多个实现,请在具有相同接口的不同类中实现它们,并在Load() 方法中使用。
【解决方案3】:

访问修饰符只处理谁可以看到代码,而不是它是如何实现的。
做你想做的最接近的方法是使用abstract classes

举个例子:

internal abstract class SongLoader //under SongLoader.cs
{
    internal async virtual Task<IEnumerable<Song>> Load();
    internal async virtual Task<Stream> OpenData();
}

internal sealed class SongLoaderImplementer : SongLoader //under SongLoaderImplementer.cs
{
    internal override async Task<IEnumerable<Song> Load() {}
    internal override async Task<Stream> OpenData() {}
}

【讨论】:

    【解决方案4】:

    对不起,我知道为时已晚,但我仍然想给出答案。 看来您的问题来自“Xamarin 大学”,所以:

    或者是否可以在一个文件中定义 Load() 而在另一个文件中定义 OpenData(),同时使用内部访问修饰符?这可能吗?怎么样?

    是的。您应该在外部取出OpenData() 方法并在每个特定于平台的项目中实现它。您不需要在“共享项目”中使用此方法。如下:

    Android 项目:

    internal class SongLoaderManager
    {
        internal static Stream OpenData(string fileName)
        {
            return Android.App.Application.Context.Assets.Open(fileName);
        }
    }
    

    IOS 项目

    internal class SongLoaderManager
    {
        internal static Stream OpenData(string fileName)
        {
            return System.IO.File.OpenRead(fileName);
        }
    }
    

    共享项目:

    public static partial class SongLoader
    {
        const string Filename = "songs.json";
    
        public static async Task<IEnumerable<Song>> Load()
        {
            using (var reader = new StreamReader(SongLoaderManager.OpenData(Filename))) 
            {
                return JsonConvert.DeserializeObject<List<Song>>(await reader.ReadToEndAsync());
            }
        }
    
        // NOT NEEDED ANYMORE
        //public static Stream OpenData()
        //{
        //    // TODO: add code to open file here.
        //    return null;
        //}
    
    }
    

    在每个平台中,您都可以定义自己的 OpenData() 方法,具有不同的行为。

    【讨论】:

      猜你喜欢
      • 2020-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-18
      • 2014-10-13
      • 2012-04-19
      • 2013-03-13
      • 2016-08-27
      • 1970-01-01
      相关资源
      最近更新 更多