【C#】C#で作成したDLLをC#で呼ぶ(静的/動的)

**もくじ**
→https://tera1707.com/entry/2022/02/06/144447

# やりたいこと
C#で作ったDLLを、C#で使いたい。


# 呼ばれる側C#（=DLL）
[VisualC#] > [Windowsデスクトップ]の中の[クラスライブラリ(.NET Framework)]を選択し、プロジェクトを作成する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352601/4f545168-ad0e-8798-49b1-8f53937db369.png)

デフォルトで、下記のようなコードが生成される。

``` class1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    public class Class1
    {
    }
}
```

ここに、DLLで行いたい処理を記述する。
今回は、下記のようにした。

``` MyCsDllClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DllTestCs
{
    public class MyCsDllClass
    {
        public List<MyData> DataList = new List<MyData>();

        /// <summary>
        /// staticなメソッド。ただの足し算を行う。
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int Add(int a, int b) => a + b;

        /// <summary>
        /// データリストに引数のデータを追加する。
        /// 追加後のデータリストの件数を返す。
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public int AddMyData(MyData data)
        {
            if (data != null)
            {
                DataList.Add(data);
            }

            return DataList.Count;
        }

        /// <summary>
        /// 引数で指定したindexを持つデータがリスト内にあればそれを返す。
        /// 無ければnullを返す。
        /// </summary>
        /// <param name="serachIndex"></param>
        /// <returns></returns>
        public MyData DataSearch(int serachIndex) => DataList.FirstOrDefault(x => x.index == serachIndex);
    }

    /// <summary>
    /// お試しデータのクラス。
    /// </summary>
    public class MyData
    {
        public int index;
        public double data;
    }
}
```

# 呼ぶ側C#（=アプリ）
まず、呼び出したいアプリ側のプロジェクトの「参照」に、上で作成したDLLを追加する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/352601/b9a8d084-a545-882b-f1e9-e3624259c21c.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/352601/43bf0821-7878-bb1c-210f-f8c35d0ea986.png)

参照を追加したら、そのDLLに含まれるクラスやメソッドを使用し、コーディングを行う。今回は、下記のようにした。

``` Program.cs
using DllTestCs;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // C#のDLLを呼ぶ(プロジェクトの参照に、DLLを追加し、このファイルの上にusingを追加)
            int a = MyCsDllClass.Add(1, 2);
            var mcdc = new MyCsDllClass();
            mcdc.AddMyData(new MyData() { index = 1, data = 1.1 });
            mcdc.AddMyData(new MyData() { index = 2, data = 2.2 });
            mcdc.AddMyData(new MyData() { index = 3, data = 3.3 });
            var result = mcdc.DataSearch(2);
            var result2 = mcdc.DataSearch(5);
        }
    }
}
```

# 備考

- C#は、DLLを作る時も呼ぶときも、C++よりもかなり簡単に作れて呼べる。(普通にクラスを作って、呼ぶ側で参照に追加するだけ)
- C++で作成したDLLをC++で呼ぶときと同じで、C#でDLLを呼ぶときも「動的」に呼べるらしい。(未検証)必要に迫られていないので、そのうちやり方確認したい。

# コード

https://github.com/tera1707/WPF-/tree/master/020_CppDllProject

# 動的呼び出し(19/04/05追記)

動的に呼び出すには、下記のようにする。

``` 動的呼び出し側サンプル.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CSharpConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            var asm = Assembly.LoadFrom("CSharpDll.dll");       // アセンブリの読み込み
            var module = asm.GetModule("CSharpDll.dll");        // アセンブリからモジュールを取得
            var Person = module.GetType("CSharpDll.Person");    // 利用するクラス(or 構造体)を取得

            if (Person != null)
            {
                // CSharpDll.Personクラスをインスタンス化.
                // コンストラクタへ引数を渡すことも可能.
                dynamic p1 = Activator.CreateInstance(Person, "Aiueo", 29);    

                // dynamicで受けているので, 面倒なプロパティ取得やメソッド取得を省略できる.
                Console.WriteLine($"name= {p1.Name}");
                Console.WriteLine($"age= {p1.Age}");
                Console.WriteLine(p1.ToString());
            }

            Console.ReadKey();
        }
    }
}
```
```  dll側サンプル.cs
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpDll
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public Person() : this("", 0) { }
        public Person(string name, int age) => (Name, Age) = (name, age);

        public override string ToString() => $"{Name} ({Age})";
    }
}
```
通常、動的な呼び出しは行わない。
使われるのは、プラグインを作る場合などにほとんど限られる。