響應式程式設計介紹
阿新 • • 發佈:2022-05-17
Dynamic Proxy
情景:
定義銀行介面,包含兩個方法 存錢和取錢
需要在原有介面基礎上記錄存錢和取錢的次數相關資訊;
Nuget:ImpromptuInterface
實現:
public interface IBankAccount { void Deposit(int amount); bool WithDraw(int amount); string ToString(); } public class BankAccount : IBankAccount {private int balance; private int overdraftLimit=-500; public void Deposit(int amount) { balance += amount; Console.WriteLine($"Deposit{amount} balance is now {balance}"); } public bool WithDraw(int amount) { if (balance- amount >= overdraftLimit) { balance-= amount; Console.WriteLine($"WithDraw{amount} balance is now {balance}"); return true; } return false; } public override string ToString() { return $"{ nameof(balance)}: {balance}"; } }public class Log<T>:DynamicObject where T:class,new() { private T subject; private Dictionary<string, int> methodCallCount = new(); public Log(T subject) { this.subject = subject; } public static I As<I>() where I:class { if (!typeof(I).IsInterface) throw new ArgumentException("Must be an Interface"); return new Log<T>(new T()).ActLike<I>(); } public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { try { Console.WriteLine($"Invoking {subject.GetType().Name}.{binder.Name} with arguments [{string.Join(',', args)}]"); if (methodCallCount.ContainsKey(binder.Name)) methodCallCount[binder.Name]++; else methodCallCount[binder.Name] = 1; result = subject.GetType().GetMethod(binder.Name).Invoke(subject, args); return true; } catch { result = null; return false; } // return base.TryInvokeMember(binder, args, out result); } public string Info { get { StringBuilder sb = new StringBuilder(); foreach (var item in methodCallCount) { sb.AppendLine($"{item.Key} Excute {item.Value} time(s)"); } return sb.ToString(); } } public override string ToString() { return $"{Info} \n{subject}"; } } class Program { static void Main(string[] args) { var ba = Log<BankAccount>.As<IBankAccount>(); ba.Deposit(500); ba.WithDraw(200); Console.WriteLine(ba); } }
執行結果: