Vài ngày trước, tôi đã viết về duck typing trong C# với interceptor. Khi đó, mã mới chỉ là một bản thử nghiệm với khá nhiều điểm còn thô. Giờ đây, nó đã trở thành một thư viện thực sự: IfItQuacks.
Mục lục
Y tuong trong 30 giay
Khai bao mot interface, danh dau phuong thuc bang [DuckTyped], sau do truyen vao bat ky doi tuong nao phu hop – khong can lop co so, khong can implements, cung khong can gan attribute vao chinh cac kieu du lieu:
using IfItQuacks;
public interface INamed
{
string Name { get; }
}
public class Person { public string Name => "Steven"; }
public class Mallard { public string Name => "Donald"; }
public partial class Greeter
{
[DuckTyped]
public string Greet(INamed first, INamed second, string greeting = "Hello") =>
$"{greeting}, {first.Name} and {second.Name}!";
}
new Greeter().Greet(new Person(), new Mallard()); // Hello, Steven and Donald!
Person va Mallard deu khong biet gi ve INamed. Source generator se kiem tra tai thoi diem bien dich xem ca hai co thanh vien Name tuong thich hay khong, sau do dieu huong loi goi qua mot adapter nho duoc tao tu dong. Khong reflection, khong dynamic. Neu doi tuong khong phu hop, ban se nhan duoc loi tu analyzer.
Neu muon luu lai doi tuong dang duck, hay chuyen doi no mot cach tuong minh:
List<INamed> names = [Duck.As<INamed>(new Person()), Duck.As<INamed>(new Mallard())];
Diem noi bat
Duoi day la phan gioi thieu ngan gon. Tai lieu huong dan co phan trinh bay day du hon.
Kieu an danh cung la duck
Day la tinh nang toi thich nhat. Kieu an danh la cac object literal, ve co ban giong nhung gi TypeScript cung cap, va chung hoat dong rat tot voi duck typing:
new Greeter().Greet(new { Name = "Steven" }, new { Name = "Donald" });
Ve co ban, ban co the viet test theo cach nay. Stub tuc thi!
public interface IPerson
{
string Name { get; }
int Age { get; }
}
public partial class AgeChecker
{
[DuckTyped]
public bool IsAdult(IPerson person) => person.Age >= 18;
}
[Test]
public void Should_detect_adults()
{
var checker = new AgeChecker();
Assert.That(checker.IsAdult(new { Name = "Steven", Age = 90 }), Is.True);
Assert.That(checker.IsAdult(new { Name = "Baby Duck", Age = 1 }), Is.False);
}
Hoac:
IPerson stub = Duck.As<IPerson>(new { Name = "Donald", Age = 90 });
List<IPerson> family =
[
Duck.As<IPerson>(new { Name = "Huey", Age = 10 }),
Duck.As<IPerson>(new { Name = "Dewey", Age = 10 }),
Duck.As<IPerson>(new { Name = "Louie", Age = 10 }),
];
Danh tinh duoc giu nguyen
Cac adapter chuyen tiep Equals, GetHashCode va ToString den doi tuong duoc boc, vi vay chung hoat dong dung trong dictionary va set. Ban cung co the lay lai doi tuong goc:
var person = new Person();
Duck.As<INamed>(person).Equals(Duck.As<INamed>(person)); // true
Duck.Unwrap(Duck.As<INamed>(person)) is Person; // true
Va con nhieu tinh nang khac
- Ho tro moi interface, bao gom ca interface cua framework:
Duck.As<IDisposable>(x), tham soIEnumerable<T>, … - Cac tham so interface khong can duck typing, chang han
ILogger, van tiep tuc chap nhan implementation,nullva gia tri mac dinh. - Interface generic nhu
IContainer<T>va cac phuong thuc[DuckTyped]generic voi tham so kieu duoc suy ra. - Event, indexer va cac thanh vien mac dinh cua interface.
- Delegate, lambda va method group cho cac interface chi co mot phuong thuc.
- Thanh vien
static abstractva toan tu thong qua rang buoc duck-typed, chang hanwhere T : IAddable<T>; bao gom ca generic math. - Phuong thuc instance va static,
ref/out,params, gia tri mac dinh va named argument. - Khong can cau hinh: chi can cai goi package, khong can thay doi file du an.
Tai nguyen
- Repository: https://github.com/linkdotnet/IfItQuacks
- Tai lieu: https://linkdotnet.github.io/IfItQuacks/
- Co che hoat dong – bao gom ca thong tin ve cac doi tuong duoc cap phat.
- Cac gioi han da biet
- Bai viet goc: Quack Quack: Duck-Typing trong C# voi Interceptor



