48326


C#にRubyにおけるmoduleに相当する機能はありますか？  
共通の処理をもたせるにはクラスの継承を利用するか、依存性の注入をするかのどちらかしかないでしょうか？

＋＋追記  
C#を昨日勉強し始めたばかりで、基本機能を把握する過程で疑問に思っただけで、特に具体的な問題に直面しているわけではありません。  
Rubyのmoduleに相当する機能に期待することは、「関連の低いクラス間でメソッドの共有”のみ”を行うこと」です。  
継承は基本的に関連するクラスで行うものですし、他の方法ですとわざわざインスタンス化する必要があったりするので  
moduleがあればシンプルでいいな、と思った次第です。

今の所,クラスのインスタンス変数に共有するメソッドをまとめたstaticなクラスのクラスインスタンス？を入れておくのが、思いついてる中で一番目的に適った方法です。  
＝＞  
Rubyの感覚で変数にクラスオブジェクトを代入出来ると思ってましたが、c#では出来ないようですね。thisをstaticメソッド内で使用することも出来ず、returnしたりすることも出来ませんし。

＋＋回答から  
c#8.0でデフォルトインターフェースメソッドが実装されるのが一番ですが、現状では拡張メソッドを使った方法が一番目的に即してるようですね。staticメソッドとしての制約は受けますが、拡張メソッドの引数の型にインターフェースを指定すれば、特定のインターフェースを継承したクラスのみにメソッドの使用を許可出来るので、不用意な使用の回避も出来ますし。


CC BY-SA 4.0
2018-09-11T04:47:04.420
48270
2018-09-12T17:33:14.677
2018-09-12T17:33:14.677
18481
18481
question
c#
C#にRubyにおけるmoduleに相当する機能はありますか？


rubyにおけるmoduleのセマンティクス(意味論)に習熟しているわけではないですが、  
関連性の低いクラスから共通して呼び出せるメソッド(あるいは関数と呼ぶほうが正しい)は  
設問者が提示している通りC#においてはstatic classとして宣言するのが妥当だと思います。

いわゆるスクリプト言語でよく使うような単なる関数をまとめあげたもの  
(まさしくモジュール、あるいはユーティリティということもある)を簡単に宣言する方法を  
C#は持ち合わせてはいません。単なる関数定義にもクラス宣言を必要とします。  
クラス依存性や継承階層を持たないクラスを作るならばそれはstaticクラスです。


CC BY-SA 4.0
2018-09-11T13:22:16.177
48284
2018-09-11T13:22:16.177
25980
48270
answer


Ruby言語は[ダックタイピング](https://ja.wikipedia.org/wiki/%E3%83%80%E3%83%83%E3%82%AF%E3%83%BB%E3%82%BF%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0)が採用されています。クラスメソッドを呼び出す際、実行時にメソッド名が一致していればそれが呼び出されるはずです。

しかし、C#言語は異なるメソッド解決方式を採用しています。具体的にはコンパイル時に呼び出し先のメソッドの存在の有無を確認します。このことは、Rubyのmodule相当を作ろうとしても、module側からは
**どのクラス** のメンバーにアクセスしようとしているのか特定できないため、クラスには全くアクセスできないことを意味します。

つまり、C#言語においてmodule相当として実現できることはクラスに一切アクセスしないプログラム的に完全に独立したモノでしかありません。この機能であればnaoki
fujitaさんの回答で提案されている`static class`が相当します。


CC BY-SA 4.0
2018-09-11T21:22:49.160
48289
2018-09-11T21:22:49.160
4236
48270
answer


関連の低いクラス間でメソッドの共有をしたいのであれば、インターフェース＋インターフェースに対する拡張メソッドの定義でやりたいことはできるかと思われます。  
共通で行いたい操作に必要なAPIをインターフェースで規定して、そのAPIを用いて行う操作を拡張メソッドにより定義します。

以下にコード実例を示します。実行例として[paiza online compiler](https://paiza.io/projects/YC-
NSAp50fbfke2DGgRhVw?language=csharp)へのリンクも貼っておきます。

AliceクラスとTomクラスはまったく異なるクラスですが、ここにIGreetableというインターフェースをもたせることで、共通の処理を記述することができます。共通処理はIGreetableExtensions内でGreetメソッドとして定義されています。拡張メソッドとして定義された静的メソッドは、あたかもインスタンスメソッドのように呼ぶことができます。呼び出す側はIGreetableExtensionsなどを明示的に参照せずに、拡張メソッドを単に`alice.Greet()`や`tom.Greet()`などと呼び出すことができます。

[code]

    using System;
    
    public class Program
    {
        public static void Main()  // TomクラスとAliceクラスに共通のGreetメソッドを生やしたい
        {
            var tom = new Tom();
            var alice = new Alice();
    
            tom.Greet();
            alice.Greet();
        }
    }
    
    interface IGreetable {  // インターフェースでNameプロパティを持つことを要求。
        string Name { get; }
    }
    
    class Tom : IGreetable { // IGreetableインターフェースを備える
        public string Name => "Tom";
    }
    
    class Alice : IGreetable{ // IGreetableインターフェースを備える
        public string Name => "Alice";
    }
    
    static class IGreetableExtensions { // IGreetableなオブジェクトにGreetメソッドを生やす
        public static void Greet(this IGreetable greetable) => Console.WriteLine($"Hello! My name is {greetable.Name}. Nice to meet you!");
    }
    
[/code]

Q. インターフェースに直接実装もたせられないのは不便では → A. C#8.0ではインターフェースに関数の実装をもたせられるようになる予定です。  
<https://dotnetcoretutorials.com/2018/03/25/proposed-default-interface-
methods-in-c-8/>

Q. IGreetableExtensionsとかいうクラスを定義しなきゃならないの気持ち悪い → A. C#8.0で
Extensionという専用構文を用意することが検討されていますので、次のバージョンで解決されるかもしれません。  
<https://blog.ndepend.com/c-8-0-features-glimpse-future/>


CC BY-SA 4.0
2018-09-12T10:05:18.417
48317
2018-09-12T10:05:18.417
30077
48270
answer


Rubyのモジュールを使う目的はだいたい次の三つです。

  1. 名前空間
  2. ユーティリティクラス
  3. Mixin

それぞれC#ではどうするのかを見ていきましょう。

**名前空間**
として使う場合はそれほど難しくありません。C#では`namespace`を使えばいいだけです。ただ、名前空間の構成の仕方が全く違いますので、名前を分けるのに使う機能として、それぞれモジュールや`namesapce`を使うと考えてください。

**ユーティリティクラス**
というのは、特定のオブジェクトやクラスから独立したメソッド類を集めた物です。Rubyではモジュールがその役目を担いますが、JavaやC#ではクラスで実装するためユーティリティクラスと言われます。Rubyでユーティリティクラスとしてモジュールを使うときは、`module_function`を使ってメソッドをモジュール関数にします。C#の場合は`static`メソッドにします。Rubyの`Math`とC#の`System.Math`がこの使い方になりますが、Rubyの方はモジュールであり、C#の方はクラスで実装されています。

最後の **Mixin**
についてですが、これは共通のメソッドを通常の継承とは別に持たせる機能です。Rubyの`Comparable`や`Enumerable`がこのMixin用に用意されたモジュールと言えます。Rubyでは`each`メソッドを適切に定義して、`Enumerable`をMixinさせると、`map`や`select`と言ったメソッドを使うことができます。このように、特定のメソッドから派生したメソッドを個別に定義せずに、共通で定義しておいて、コードを簡潔にするという機能です。Mixinと同様の働きができる物として、trait(PHP等)や多重継承(C++、Python等)があります。多重継承が出来ない単一継承だからこそ、この機能があると言っても良いでしょう。

このMixinまたはそれと同等の機能についてですが、現在のバージョン(7.2)では、C#には **ありません**
。ただ、ライバルであるJavaにはインターフェースデフォルトメソッドというMixin相当の機能が搭載されたため、将来同じような物が搭載される可能性はあります(私は可能性が低いと思っていますが)。

さて、Rubyの`Enumerable`相当になりそうなものにC#には`System.Collections.Generic.IEnumerable<T>`があります。こちらも同様に、`GetEnumerator()`メソッドを適切に定義すれば`Select()`や`Wherer()`などがメソッドの
**ように**
つかえるようになります。あれ、結局はRubyの`Enumerable`と同じことができているじゃないかと思うでしょう。それは半分正解で半分間違いです。

これは **拡張メソッド**
というC#の機能であり、拡張メソッド自体はただの`static`メソッドにすぎません。C#は呼び出しの方に工夫をしました。ユーティリティクラスを作るような形で`static`メソッドを作成するのですが、このとき拡張メソッドとして定義する(仮引数に`this`修飾子をつける)とあたかもインスタンスメソッドのように呼び出せるようにしたのです。

[code]

    using System;
    public interface IIntNum
    {
            int Value();
    }
    public static class IntNum
    {
            public static int Double(this IIntNum num)
            {
                    return num.Value() * 2;
            }
    }
    public class IntBox : IIntNum
    {
            public int x;
            public int Value()
            {
                    return this.x;
            }
    }
    public class MainClass
    {
            public static void Main(string[] args)
            {
                    var ib = new IntBox{x = 3};
                    var x = IntNum.Double(ib); // 通常のstaticメソッド呼び出し
                    Console.WriteLine(x); // 6
                    var y = ib.Double(); // 拡張メソッドとしての呼び出し
                    Console.WriteLine(y); // 6
            }
    }
    
[/code]

これは、Mixinやその他の類似した機能のように、インスタンスメソッドとしてそのクラスに追加されたわけではありません。 **見せかけ上**
インスタンスメソッドのように書けるというだけで、その本質は`static`メソッドのままです。しかし、実用上はMixin相当であり、十分であると考えても良いでしょう。

ということで、C#にはMixinまたはそれ相応の機能はありませんが、拡張メソッドを用いることで、見せかけ上同じようにできるとなります。(ただし、その仕組みは全く異なる物ですので、同じことが必ずできるというわけではないことに注意してください。)


CC BY-SA 4.0
2018-09-12T13:45:49.273
48326
2018-09-12T13:45:49.273
7347
48270
answer