Tìm hiểu về reflection trong .NET

Trong bài viết này, chúng ta sẽ đi qua 3 phần chính: Assembly, Reflection, và cách thực thi 1 phương thức trong reflection.

Assembly

Assembly là một thư viện gồm các đoạn code đã được dịch sẵn, do đó có thể chạy được bởi nhiều chương trình khác. Các chương trình khác chỉ cần bổ sung thư viện này và gọi các hàm trong thư viện, các hàm sẽ chạy ngay (do đã được dịch sẵn) mà không cần bộ dịch ngôn ngữ tương ứng và người viết chương trình cũng không cần tốn công viết lại các hàm đó nữa.
Một vài Properties trong Assembly


public virtual string CodeBase { get; } //Gets the location of the assembly as specified originally, for example, in an AssemblyName object.

public virtual string FullName { get; } //Gets the display name of the assembly.

public virtual IEnumerable DefinedTypes { get; } //Gets a collection of the types defined in this assembly.

public virtual IEnumerable Modules { get; } //Gets a collection that contains the modules in this assembly.
Ví dụ: Load assembly từ 1 type

public class Student
{
 public string FullName { get; set; }
 public int Class { get; set; }
 public DateTime DateOfBirth { get; set; }
 public string GetCharacteristics()
 {
  return "";
 }
}

private static void GetAssemblyFromType(Type t)
{
 var assembly = System.Reflection.Assembly.GetAssembly(t);
 Console.WriteLine("Assembly Name: " + assembly.GetName().Name);
 Console.WriteLine("Version: " + assembly.GetName().Version);
}
Kết quả:
Assembly Name: ReflectionInAction
Version: 1.0.0.0
VD 2: Load assembly từ Name và file DLL

private static void CallReflection()
{
 Utilities.GetAssemblyFromAssemblyName("Services");

 var fileInfo = new FileInfo(Assembly.GetEntryAssembly().Location);

 var executingDll = Path.Combine(fileInfo.DirectoryName, "Services.dll");

 Utilities.GetAssemblyFromDll(executingDll);
}

public static void GetAssemblyFromCallingMethod()
{
 var assembly = System.Reflection.Assembly.GetCallingAssembly();
 Console.WriteLine("Assembly Name: " + assembly.GetName().Name);
 Console.WriteLine("Version: " + assembly.GetName().Version.ToString());
}

public static void GetAssemblyFromAssemblyName(string name)
{
 Console.WriteLine("Get Assembly From Assembly Name");
 var assembly = System.Reflection.Assembly.Load(name);
 Console.WriteLine("Assembly Name: " + assembly.GetName().Name);
 Console.WriteLine("Version: " + assembly.GetName().Version.ToString());
}
Kết quả:
Get Assembly From Assembly Name
Assembly Name: Services
Version: 1.0.0.0
Get Assembly From File Dll
Assembly Name: Services
Version: 1.0.0.0

Reflection là gì?

Reflection cung cấp các đối tượng (kiểu Type) mô tả các assembly, các module và các type. Bạn có thể sử dụng reflection để tạo tự động một đối tượng của một type, liên kết type với một đối tượng hiện có, hoặc lấy type từ một đối tượng hiện có và gọi các phương thức của nó hoặc truy cập các trường và thuộc tính của nó. Nếu bạn có sử dụng các attribute trong code, reflection sẽ cho phép bạn truy cập các attributes đó.

Type and type info

Lớp System.Type là một abstract class đại diện cho các kiểu dữ liệu: kiểu lớp, interface, mảng, giá trị, kiểu liệt kê (enumberation types), kiểu tham số, …
TypeInfo chứa những định nghĩa về Type.

private static void Example1()
{
 var studentInfo = typeof(Student).GetTypeInfo();
 var declaredProperties = studentInfo.DeclaredProperties;
 var declaredMethods = studentInfo.DeclaredMethods;
 Console.WriteLine("-------Declared Properties:------");
 foreach (var prop in declaredProperties)
 {
  Console.WriteLine(prop.Name);
 }
 Console.WriteLine("-------Declared Methods:------");
 foreach (var method in declaredMethods)
 {
  Console.WriteLine(method.Name);
 }
}

Type chứa dữ liệu tham chiếu

private static void Example2()
{
 var studentType = typeof(Student);
 var name = studentType.Name;
 var ns = studentType.Namespace;
 Console.WriteLine("Name: " + name);
 Console.WriteLine("Namespace: " + ns);
}

Fields

Reflection cho phép liệt kê các fields và các properties theo tên và giá trị của chúng.
VD:
public class MyClass
{
 public string Name { get; set; }
 public static int TheField;
 public void SayHello() { }
}

static void Main(string[] args)
{
 Type type = typeof(MyClass); // Get type pointer
 FieldInfo[] fields = type.GetFields(); // Obtain all fields
 foreach (var field in fields) // Loop through fields
 {
  string name = field.Name; // Get string name                
  Console.WriteLine(name);
 }
}
Kết quả:

Thực thi một phương thức

Để thực thi 1 phương thức, bạn dùng hàm GetMethod() kết hợp với thông tin MethodInfo.
Giá trị trả về của phương thức GetMethod là một đối tượng kiểu System.Reflection.MethodInfo chứa các thông tin về phương thức.
VD:

var myClass = new MyClass();
var myType = myClass.GetType();
// get method info SayHello
var myMethodInfo = myType.GetMethod("SayHello");

// invoke method SayHello with parameter null
myMethodInfo.Invoke(myClass, null);
Kết quả:
Hello
VD 2: Thực thi phương thức với parameter name
Thêm hàm SayHello với parameter name thì cùng đoạn code trên, bạn sẽ bị báo lỗi:
System.Reflection.AmbiguousMatchException: Ambiguous match found
Khắc phục: gọi hàm GetMethod và truyền thêm type:

var myClass = new MyClass();
var myType = myClass.GetType();
// get method info SayHello
var myMethodInfo = myType.GetMethod("SayHello", new[] { typeof(string) });
var mParams = new object[] { "Nhatkyhoctap" };
// invoke method SayHello with parameter null
myMethodInfo.Invoke(myClass, mParams);
Kết quả:
Hello Nhatkyhoctap
VD 3: gọi hàm generic

var myClass = new MyClass();
var myType = myClass.GetType();
// get method info SayHello
var myMethodInfo = myType.GetMethod("SayHi", new[] { typeof(string) });
var mParams = new object[] { "Nhatkyhoctap" };            
var genericMethodInfo = myMethodInfo.MakeGenericMethod(typeof(string));
genericMethodInfo.Invoke(myClass, mParams);   
Kết quả:
Type: System.String
Hello Nhatkyhoctap
Tạo đối tượng Class Activator chứa các method dùng để tạo ra đối tượng cục bộ hoặc từ xa, hoặc lấy tham chiếu đến các đối tượng từ xa hiện có. Lớp này không thể được thừa kế. Vd:

var dateTime = (DateTime)Activator.CreateInstance(typeof(DateTime));
Console.WriteLine(dateTime.Date);
Kết quả:
1/1/0001 12:00:00 AM
VD 2:
Trường hợp tạo đối tượng kèm parameter

public class Category
{
 public Category(string name)
 {
  Name = name;
 }

 public int Id { get; set; }
 public string Name { get; set; }

 public string UrlSlug { get; set; }

 public string Description { get; set; }
}
Hàm Main:

static void Main(string[] args)
{
 // create instance of class Category
 var category = (Category)Activator.CreateInstance(typeof(Category), "Nhatkyhoctap");
 Console.WriteLine(category.Name);
}
Kết quả:
Nhatkyhoctap

Tham khảo

https://www.dotnetperls.com/reflection
https://dotnetcademy.net/Learn/4/Pages/3

Chúc các bạn thành công!
Nhatkyhoctap's blog