C#lambda式を使用して関数をパラメータまたは属性としてクラス間で渡す

5468 ワード

符号化する時、初めはwinformの下で簡単なテスト開発を行ったので、それからコードが多くなって、違うクラスに分けたいと思っていましたが、元のテストは同じformの下にあるので、関数呼び出しに便利ですが、クラスをまたぐと、この関数の結合度が高すぎることがわかります.どうやってクラスに解けるか分からないほどだ.この場合,依頼タイプのFuncとActionを用いて実現してみるとよい.
次は最初のテストでwinformに書いた簡単なコードです.
 
using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Text.RegularExpressions;

using System.Threading.Tasks;

using System.Windows.Forms;



namespace FunctionPass

{

    public partial class FormMain : Form

    {

        public FormMain()

        {

            InitializeComponent();

        }





        private void buttonTest_Click(object sender, EventArgs e)

        {

            test();

        }



        public void test()

        {

            string sourceStr = collectData();

            string digitStr = fetchDigit(sourceStr);

            MessageBox.Show("source:" + sourceStr + "\r
digit:" + digitStr); } public string collectData() { return Guid.NewGuid().ToString(); } public string fetchDigit(string sourceStr) { Regex regex = new Regex(@"\d*"); MatchCollection digitCollection=regex.Matches(sourceStr); string digitStr = ""; foreach (Match digitMatch in digitCollection) { digitStr += digitMatch; } return digitStr; } } }
ここではcolloectData関数でデータを収集し、fetchDigitでデータの数字を抽出した後、test関数で結果を表示します.
 
今、私は表示結果を別のクラス(例えばTestクラス)にして、後でもっと拡張したいと思っています.
 
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;



namespace FunctionPass

{

    public class Test

    {

        public void test()

        {

            string sourceStr = collectData();

            string digitStr = fetchDigit(sourceStr);

            MessageBox.Show("source:" + sourceStr + "\r
digit:" + digitStr); } } }
collectDataとfetchDigitは定義されていないことに気づきますが、どうすればいいのでしょうか.委任タイプのプロパティで渡すことができます.以下、修正したコードを示します.
 
 
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;



namespace FunctionPass

{

    public class Test

    {

        public Func<string> collectData { get; set; }

        public Func<string,string> fetchDigit { get; set; }

        public void test()

        {

            string sourceStr = collectData();

            string digitStr = fetchDigit(sourceStr);

            MessageBox.Show("source:" + sourceStr + "\r
digit:" + digitStr); } } }
では、formのcollectDataとfetchDigit関数をどのように伝えますか?formで属性に値を割り当てるように直接値を割り当てることができます.コードは以下の通りです
 
 
  private Test test_ = new Test();//               

        private void buttonTest_Click(object sender, EventArgs e)

        {

            test_.collectData = collectData;//  

            test_.fetchDigit = fetchDigit;//  

            test_.test();

        }        

 
必要に応じてcollectDataとfetchDigit関数をformからクラスに独立させたいと考え、DataDealというクラスを構築しました.コードは以下の通りです
 
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Text.RegularExpressions;

using System.Threading.Tasks;



namespace FunctionPass

{

    public class DataDeal

    {

        public string collectData()

        {

            return Guid.NewGuid().ToString();

        }



        public string fetchDigit(string sourceStr)

        {

            Regex regex = new Regex(@"\d*");

            MatchCollection digitCollection = regex.Matches(sourceStr);

            string digitStr = "";

            foreach (Match digitMatch in digitCollection)

            {

                digitStr += digitMatch;

            }

            return digitStr;

        }

    }

}

このときformのbuttonTest_Clickメソッドではtest_.collectDataと test_.fetchDigitの付与値は変更する必要があります.代修後のコードは以下の通りです.
 
private Test test_ = new Test();//               

        private DataDeal dataDeal_ = new DataDeal();//               

        private void buttonTest_Click(object sender, EventArgs e)

        {

            test_.collectData = dataDeal_.collectData;

            test_.fetchDigit = dataDeal_.fetchDigit;

            test_.test();

        }   
コードが正常に実行されました.
 
DataDealクラスのcollectDataとfetchDigitで他の操作を行った場合、インスタンスメソッドの依頼が空の「this」を持つことができないなどの異常を引き起こす可能性があります.この場合、formの付与プロセスでいくつかの処理が必要になります.これはlambda式で実現できます.修正後のコードは次のようになります.
 
test_.collectData = () => { return dataDeal_.collectData(); };

            test_.fetchDigit = (sourceStr) => { return dataDeal_.fetchDigit(sourceStr); };
したがってクラス間の関数伝達については,属性に対する操作であり,タイプがFuncやActionなどの委任タイプになっただけである.
 
ここで注意したいのは、
Funcは戻り値がある場合に使用します.
Actionは、戻り値がない場合に使用します.
転載は出典http://blog.csdn.net/xxdddail/article/details/9849111を明記してください