0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Taskを学ぶ前のあなたに-ActionとFunc理解してます?-

Posted at

初めに

 だんだんとプログラミングに慣れてくると並列処理について知ることになると思います。C#で言うならばParallel.ForだったりTaskだったりです。この二つを学ぼうとするとき障壁になるのAction<>Func<>といった、なんかよくわからないクラスたちです。
 一言で言ってしまうとこれらのクラスはDelegate型と非常に密接に関わっています。
この記事でそのもやもやを少しでも解消できたら幸いです。
 なおサボりたい見やすさ的に最低限のサンプルコードだけを載せます。

Delegate型って何?

 簡単に言ってしまうとメソッドの参照を格納することができる型です。例を見てみましょう。一緒に手を動かしてみるとさらに理解は深まりますよ!

Program.cs
//namespaceなどは省略しています。
        static void Main(string[] args)
        {
            Program p = new Program();

            SampleDelegate d1 = new SampleDelegate(p.G);//p.G()じゃない
            d1 += p.H;
            d1.Invoke();

        }
        
        public delegate void SampleDelegate();//delegate型は一種のクラスのようなもの
        
        public void G()
        {
            Console.WriteLine("G");
        }
        public void H()
        {
            Console.WriteLine("H");
        }
        

このコードを実行するとコンソールに

コンソール
G
H

と表示されるはずです。コードを見たらわかりますが先に P.Gと代入しています。ここを先にP.Hを代入すれば.Invoke()したとき、先にP.Hが実行されます。他にも-=を利用するとすでに代入されているメソッドの参照を消せたりするので、まあそこらへんは自分で調べてください。(丸投げ)

そもそもどこでDelegate型が使われるのか

 あるボタンのクリックイベントハンドラに関数を渡すコードです。

Background.cs
//xamlなどで<Button Name="button">みたいにすれば
button.Click += Tekitou();

ここで.Clickに注目してください。これは厳密に言わなくてもeventです。しかしeventdelegateを基にして作ったものなので同じような動作をします。これはあくまで一例なのでほかにも探してみてください。(丸投げPart2)

いちいちDelegate型を宣言するのがだるい

 見ての通り、戻り値によって宣言する必要があります。

Sample.cs
//void関数用
public delegate void SampleDelegate();
//int関数用
public delegate int SampleDelegate2();
//string関数用
public delegate string SampleDelegate();
...

:scream: となります。ここに関数へ渡すための引数のことも考えるとさらに定義が必要となり、
:scream: :scream: :scream:となります。

Q.では頭のいい人たちはどうしたのか。
A.ジェネリック型で使いまわせるAction<>とFunc<>を定義しよう!:v:

Actionについて

 これは主に戻り値のない関数の参照を格納するためにあります。

Sample.cs
       static void Main(string[] args)
       {
           Action<string,string,string> action = new Action<string, string, string>(S);
           //action += S2;
           action.Invoke("a", "b", "c");

       }

        public static void S(string a,string b, string c)
       {
           Console.WriteLine(a);
           Console.WriteLine(b);
           Console.WriteLine(c);
       }

       public static void S2(string a, string b)
       {
           Console.WriteLine(a);
           Console.WriteLine(b);
       }
コンソール
a
b
c

  Actionの<>の中はactionが参照に持つ関数へ渡す引数です。コードではstring型を第三引数まで取っています。そして関数`S(string a,string b, string c)`に注目してください。これもstring型を第三引数まで取っています。Action<>と引数が一致しない場合、その関数の参照をactionに渡すことはできません。
 試しにactionへS2の参照を渡してみてください。必ずエラーが起きます。これは後述するFunc<>でも同様です。

Funcについて

Func<>Action<>とほぼ同じ動作をしますが、

Func<string,string,string> func //~~~省略

このように書かれたとき、Func<>最後の引数funcが参照に持つ関数の戻り値となります。つまりFunc<>戻り値がある関数の参照を格納するためにあります。コードで見てみましょう。

Sample.cs
       static void Main(string[] args)
       {
           Func<string,string,string,string> func = new Func<string, string, string, string>(S);
           func += S2;

           var results = new List<string>();//戻り値を取得するためのList
           foreach (var item in func.GetInvocationList())
           {
               if(item is Func<string, string, string, string> f)
               {
                   var result = f.Invoke("a","b","c");
                   Console.WriteLine(result.ToString());
               }
           }

       }

       public static string S(string a,string b,string c)
       {
           return a + b + c;
       }

       public static string S2(string a, string b,string c)
       {
           return c + b + a;
       }
   
コンソール
abc
cba

 見ての通り戻り値があるためActionより複雑になります。またforeach内の処理は書き方がいくらかあるので試してみてください。

最後に

 こう考えるとActionFuncはとても便利なものですね。これらはTaskなどで遊ぶ際でも出てくるのでみっちり抑えておいて損はないでしょう。この記事で少しでもモヤモヤがなくっていると幸いです。お疲れさまでした。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?