[C#] 55.namespaceとusing、そしてpartialの使い方


Study / C#    作成日付 : 2021/10/21 18:51:39   修正日付 : 2021/10/21 18:52:48

こんにちは。明月です。


この投稿はC#でのnamespaceとusing、そしてpartialの使い方に関する説明です。


namespace

C#では最小単位のオブジェクト(Object)をクラスだと説明しました。

link - [C#] 10. クラスを作成する方法(コンストラクタ、デストラクタ)


我々が実行関数(Main)を使ってもその関数は必ずクラスの中で含めなければならないです。つまり、関数だけには使えません。

それで我々がプログラムを扱ったら様々なライブラリを連結して色々ソースを作成することになります。その場合、クラス名がすべて別々に作成することが可能かな?参考にクラスはオーバーライド(override:同じ名で別の処理)ができないです。

同じ名のクラスを作成すると必ずエラーが発生します。


そうすると我々がプログラムを作成する時にはそれを気を付けて作成すると思っても、オープンライブラリを連結して使う時にそのライブラリ中であるクラス名が絶対に重複されないか?可能性が十分にあります。

それなら我々がライブラリを連結して使わなければならないなのにクラスが重複になって実行されません。


それを避けるためにnamespaceがあります。

using System;
// Test1の名のnamespace
namespace Test1
{
  // Nodeクラス
  class Node
  {
    // コンソール出力関数
    public void Print()
    {
      // コンソール出力
      Console.WriteLine("Test1.Node");
    }
  }
}
// Test2の名のnamespace
namespace Test2
{
  // Nodeクラス
  class Node
  {
    // コンソール出力関数
    public void Print()
    {
      // コンソール出力
      Console.WriteLine("Test2.Node");
    }
  }
}
// Exampleの名のnamespace
namespace Example
{
  // 実行関数があるクラス
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // Test1のnamespaceの中であるNodeクラス
      var test1 = new Test1.Node();
      // 関数実行
      test1.Print();
      // Test2のnamespaceの中であるNodeクラス
      var test2 = new Test2.Node();
      // 関数実行
      test2.Print();

      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


namespaceを二つに分けてclassを生成すれば同じclass名でも生成が可能です。正解にはTest1.Node名とTest2.Node名のクラスなので別のクラス名です。

このように別のnamespaceをユニークに指定しておいたら別のライブラリとクラス名が衝突する可能性がありません。

using

でも、namespaceは重複宣言が可能です。

using System;
// Aの名のnamespace
namespace A
{
  // Bの名のnamespace
  namespace B
  {
    // Cの名のnamespace
    namespace C
    {
      // クラス
      class Node
      {
        // コンソール出力関数
        public void Print()
        {
          // コンソール出力
          Console.WriteLine("Hello world");
        }
      }
    }
  }
}
// Exampleの名のnamespace
namespace Example
{
  // 実行関数があるクラス
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // Aのnamespaceの中で、Bのnamespaceの中で、Cのnamespaceの中であるNodeクラス
      var test1 = new A.B.C.Node();
      // 関数実行
      test1.Print();

      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


上の例ではnamespaceをA、B、Cで作成しましたが、この命名が長くなると、インスタンスを生成する時にクラス名が長くなります。

それを短くするためにusingキーワードを使います。

using System;
// Aの名のnamespace
namespace A
{
  // Bの名のnamespace
  namespace B
  {
    // Cの名のnamespace
    namespace C
    {
      // クラス
      class Node
      {
        // コンソール出力関数
        public void Print()
        {
          // コンソール出力
          Console.WriteLine("Hello world");
        }
      }
    }
  }
}
// Exampleの名のnamespace
namespace Example
{
  // ここ以降のソースはA.B.Cのネームスペースの省略が可能
  using A.B.C;
  // 実行関数があるクラス
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // Aのnamespaceの中で、Bのnamespaceの中で、Cのnamespaceの中であるNodeクラス(namespaceが省略)
      var test1 = new Node();
      // 関数実行
      test1.Print();

      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


usingを使ってnamespaceを指定するとusingを書いたコードライン以降はA.B.Cを書いてなくてもA.B.Cのクラスを使えます。

上の例では私が説明しやすくするために一つのページで説明しましたが、普通はクラス別でファイル(.cs)を作成するしnamespace別でフォルダを作成するため、usingをソースの最初のラインに作成します。


そうなら最初の例みたいに同じクラスはどのように処理するかな?

using System;
// Test1の名のnamespace
namespace Test1
{
  // Nodeクラス
  class Node
  {
    // コンソール出力関数
    public void Print()
    {
      // コンソール出力
      Console.WriteLine("Test1.Node");
    }
  }
}
// Test2の名のnamespace
namespace Test2
{
  // Nodeクラス
  class Node
  {
    // コンソール出力関数
    public void Print()
    {
      // コンソール出力
      Console.WriteLine("Test2.Node");
    }
  }
}
// Exampleの名のnamespace
namespace Example
{
  // ここ以降のソースはTest1のネームスペースの省略が可能
  using Test1;
  // ここ以降のソースはTest2のネームスペースの省略が可能
  using Test2;
  // 実行関数があるクラス
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // Test1のnamespaceの中であるNodeクラス
      var test1 = new Test1.Node();
      // 関数実行
      test1.Print();
      // Test2のnamespaceの中であるNodeクラス
      var test2 = new Test2.Node();
      // 関数実行
      test2.Print();

      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


この場合はNodeのクラス区分ができないので、usingを使ってもクラスの前でnamespace名を含めて作成しなければならないです。


そしてクラスがstaticになっている場合はクラスの中のクラスもすべてstaticになっている場合もあります。

それをユーティリティ関数クラスと言います。

using System;
// Utilの名のnamespace
namespace Util
{
  // commonの静的クラス
  static class Common
  {
    // コンソール出力関数
    public static void Print()
    {
      // コンソール出力
      Console.WriteLine("Hello world");
    }
  }
}
// Exampleの名のnamespace
namespace Example
{
  // Util namespaceのCommonクラス
  using static Util.Common;
  using static System.Console;
  // 実行関数があるクラス
  class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // using staticを宣言しましたので、内部関数みたいに使用可能。
      Print();

      // 任意のキーを押してください
      WriteLine("Press any key...");
      ReadLine();
    }
  }
}


namespaceとクラス名まで省略することができます。

Print関数の下で我々がずっと使ったConsole.WriteLineもConsoleのクラス名を省略しました。

partial

元々は命名法によりnamespaceはフォルダ名、classはファイル名と一致しなければならない規約があります。

なので一つのファイルですべてのソース内容を作成しません。


でも、一つのファイルで一つのクラスを作成すると思っても仕様によりクラスのサイズがすごく大きくなる場合もあります。クラスの一つのソースライン数が何万行になる可能性もあります。

その場合、ソースが長くなるので可読性がすごく悪くなるため、ファイルを分割してクラスを作成したい時もあります。

using System;
namespace Example
{
  // Programクラス分割
  partial class Program
  {
    // 実行関数
    static void Main(string[] args)
    {
      // 関数呼び出す。
      Print();

      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}
using System;
namespace Example
{
  // Programクラス分割
  partial class Program
  {
    // コンソール出力関数
    public static void Print()
    {
      // コンソール出力
      Console.WriteLine("Hello world");
    }
  }
}


partialキーワードを使ったら二つのファイルで一つのクラスを分割して作成することが可能です。ここの注意点はpartialがないクラスでpartialを使ってクラスを拡張する概念ではありません。

言い直してStringクラスにpartial class Stringを使ってもクラス拡張になることではなく、エラーになります。実はクラスがかってに拡張されたらNGですね。逆に言えばpartialキーワードを使ったら何処でも拡張ができる概念です。

つまり、ライブラリ配布用(dll)を開発する時には注意しなければならないですね。


ここまでC#でのnamespaceとusing、そしてpartialの使い方に関する説明でした。


ご不明なところや間違いところがあればコメントしてください。

#C#
最新投稿