C#動態創建接口的實現實例對象
本文簡單介紹如何動態創建接口interface的實現實例對象,包含兩個知識點:
1.如何獲取接口interface的所有實現實例對象?
2.如何判斷實例對象的構造函數是否有參數?
準備工作
首先新建一個名為IAnimal的interface接口對象,並定義一個Cry方法。
namespace DynamicCreate
{
/// <summary>
/// 動物
/// </summary>
public interface IAnimal
{
/// <summary>
/// 叫
/// </summary>
public void Cry();
}
}
然後,我們分別新建一個Dog,Cat對象,並分別實現Cry方法。
其中,Dog的構造函數中包含一個名為name的參數。
namespace DynamicCreate
{
/// <summary>
/// 狗
/// </summary>
public class Dog : IAnimal
{
/// <summary>
/// 名字
/// </summary>
private string _name { get; }
/// <summary>
/// 有參構造函數
/// </summary>
/// <param name="name">狗名</param>
public Dog(string name)
{
_name = name;
}
/// <summary>
/// 狗叫
/// </summary>
public void Cry()
{
Console.WriteLine($"{_name}汪汪汪");
}
}
}
Cat的構造函數則為無參構造函數。
namespace DynamicCreate
{
/// <summary>
/// 貓
/// </summary>
public class Cat : IAnimal
{
/// <summary>
/// 無參構造函數
/// </summary>
public Cat()
{
}
/// <summary>
/// 貓叫
/// </summary>
public void Cry()
{
Console.WriteLine("喵喵喵");
}
}
}
常規的調用方法如下所示。
IAnimal animal_Dog = new Dog("旺財");
animal_Dog.Cry();
IAnimal animal_Cat = new Cat();
animal_Cat.Cry();
運行結果如圖所示

如果我們想要一次性將所有實現了IAnimal接口對象Cry方法的實例全部執行一遍,只能一個對象一個對象的初始化,然後調用cry方法。這樣太麻煩,我們可以通過動態創建對象並執行對象的方法來實現這個效果。
下面,我們將開始動態創建所有實現。第一步,我們需要先獲取到所有實現了IAnimal實例對象。
1.如何獲取接口interface的所有實現實例對象?
通過反射來獲取當前項目中的程序集對象列表,並根據程序集對象的類型來獲取繼承或實現了IAnimal接口的對象列表。
//獲取實現接口IAnimal的實例對象
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IAnimal))))
.ToList();
我們將結果打印出來看一下
foreach (Type t in types)
{
Console.WriteLine(t.Name);
}

現在,我們已經得到了所有實現IAnimal接口的實例對象。講道理來說,我們就可以用Activator動態創建這些對象了。我們可以使用下面的代碼來實現批量動態創建對象。
foreach (Type t in types)
{
var animal = (IAnimal)Activator.CreateInstance(t)!;
animal.Cry();
}
然而,卻出現一個錯誤提示:Dog不包含一個無參構造函數。

所以,創建時需要將Dog的構造函數參數name傳遞進去,如下所示。
foreach (Type t in types)
{
var animal = (IAnimal)Activator.CreateInstance(t, new object[] { "阿黃" })!;
animal.Cry();
}
然而,再次提示:Cat的構造函數不存在。

這是因為Cat不包含一個帶參數的構造函數,所示無法初始化Cat對象。所以,我們需要判斷對象是否是有參構造函數或無參構造函數。
2.如何判斷實例對象的構造函數是否有參數?
我們可以通過GetConstructors方法來獲取對象的構造函數集合,並通過GetParameters方法獲取到構造函數的參數集合,判斷構造函數的參數集合是否為空即可判斷該對象的構造函數是否為有參或無參構造函數。
foreach (Type v in types)
{
if (v.GetConstructors().Any(x => x.GetParameters().Any()))
{
Console.WriteLine($"{v.Name}=>有參構造函數");
}
else
{
Console.WriteLine($"{v.Name}=>無參構造函數");
}
}

現在,我們可以愉快的創建對象,並調用對象的方法了。
foreach (Type t in types)
{
IAnimal animal;
if (t.GetConstructors().Any(x => x.GetParameters().Any()))
{
//有參構造函數
//動態創建IAnimal的有參構造函數實現實例對象Dog
animal = (IAnimal)Activator.CreateInstance(t, new object[] { "阿黃" })!;
}
else
{
//無參構造函數
//動態創建IAnimal的無參構造函數實現實例對象Cat
animal = (IAnimal)Activator.CreateInstance(t, new object[] { })!;
}
animal.Cry();
}

最後,附上完整代碼,請大神們不要噴我。


