本文簡單介紹如何動態建立介面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(); }
最後,附上完整程式碼,請大神們不要噴我。