51529


提示コードを実行すると`test`クラスのコンストラクターで例外が発生する原因を知りたいです。  
演算子のオーバーロードをコメントにするとエラーがなくなりますので演算子のオーバーロードが原因と思われますが。対処法がわからず困っています。  
また  
`try catch`構文を使ってその例外を出力したいのですがクラス内ではその構文がエラーになるため  
使えません、  
出力方法と解決法、原因などを教えてくれますでしょうか？

[code]

    namespace ConsoleApp1
    {
        class Program
        {
    
            //delegate void test_del(ref int t);
    
            class test
            {
                public int x { get; set; }
    
    
                public test() { }
    
                public static test operator +(test a, test b)
                {
                    //Console.WriteLine("演算子+");
                    test t = new test();
    
                    a.x = 3;
                    t = a + b;
                    return t;
    
                }
    
                public void output()
                {
                    Console.WriteLine("x:" + x);
                }
            }
    
    
            static void Main(string[] args)
            {
                try
                {
                    test a = new test();
                    test b = new test();
                    test c = new test();
                    c = a + b;
                    c.output();
                }catch(Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
    
                Console.ReadKey();
            }              
        }
    }
    
[/code]


CC BY-SA 4.0
2018-12-26T06:11:20.720
51523
2018-12-28T07:20:52.537
2018-12-26T07:39:29.990
2238
question
c#
C# 演算子のオーバーロードで原因の不明の例外が発生する原因を知りたい。


エラーメッセージはとてもとても重要です。質問中にエラーメッセージを省略することなく記載することをお勧めします。

で、今回起きているのは `System.StackOverflowException` ですね？ そうであるとして（違うはずがないのですが）

`test.operator+` 中で `test`
の加算を行っている＝自分自身を再帰呼び出ししていて終了条件が無いため無限再帰してスタックオーバーフローに至っています。ソースコードに記述されている通りの、期待される動作がきっちり観測されていることになります。

どう直すとよいかは「あなたが何をしたいのか」次第ですが、何がしたいのか、意図なり案件なりが提示コードから読み取れないのでこれ以上のアドバイスは今のところできません。

* * *

とはいえよくある誤りぽいのでもうちょっと解説とか。サンプルのためのサンプルでは面白くないので少し実用できるネタとして複素数を考えてみましょう
(`System.Numerics.Complex` は既にありますがこれの再実装ってことで)

直交座標系で表示するとしたら複素数クラスの基本は

[code]

    public class OreComplex
    {
        public double re;
        public double im;
        public OreComplex(double r, double i)
        {
            re = r;
            im = i;
        }
    }
    
[/code]

これに加算演算子 `operator+` を [c#](/questions/tagged/c%23 "'c#' のタグが付いた質問を表示")
流に実装するとなると、クラスの `public static` メンバにしなさいということなので `public static OreComplex
operator +(OreComplex lh, OreComplex rh)` を「複素数の加算」になるよう適切に実装することになります。

さて言語を問わず `OreComplex` の加算という操作は  
\- `OreComplex` のメンバの演算で定義できる場合のみ考慮でき  
\- 加算元の `OreComplex` インスタンスのどちらとも異なる新しい `OreComplex` インスタンスが生成される  
ということになります。となると典型的コードは

[code]

    public static OreComplex operator +(OreComplex lh, OreComplex rh)
    {
        return new OreComplex(lh.re + rh.re, lh.im + rh.im);
    }
    
[/code]

このコードは「 `OreComplex` の加算」という処理が「 `OreComplex` のメンバの演算→新しい `OreComplex`
の生成」で実装できているのでプログラマの期待通りに動作します。質問で提示されたコードは `test` の加算が `test`
のメンバの演算で定義できていない、 **`test` の加算中に `test`
の加算を誤って行っている**ので、結果的に無限再帰に陥っています。演算子を自分で定義する際に自分自身を呼んでしまうというのは誰でもよくやりがちなミスですが、提示例はまさにこのミスを犯しています。

無限ループに陥らないよう修正すれば `try ... catch` も必要ないので書かなくて済みます。

演習１：ここまでで示された `OreComplex` で実際に加算するサンプルプログラムを完成させなさい

演習２：乗算 `operator *` を実装して使ってみなさい


CC BY-SA 4.0
2018-12-26T06:54:43.937
51529
2018-12-28T07:20:52.537
2018-12-28T07:20:52.537
8589
8589
51523
answer