C#中ExpandoObject是否有实例访问器?如何添加全名获取方法?
你的现有实现完全没问题,不过确实有几种其他方式能实现这个需求,每种各有适用场景,我给你梳理一下:
1. 显式转换为字典,减少闭包依赖
你可以利用ExpandoObject本身实现了IDictionary<string, object>接口的特性,直接从字典中读取属性值。这种写法虽然还是用到了外部的obj变量,但逻辑更清晰,也能避免闭包可能带来的意外(比如后续obj被重新赋值为其他对象的情况):
dynamic obj = new ExpandoObject(); obj.FirstName = "John"; obj.LastName = "Doe"; obj.GetFullName = new Func<string>(() => { var self = (IDictionary<string, object>)obj; return $"{self["FirstName"]} {self["LastName"]}"; });
2. 用扩展方法复用逻辑
如果你的多个ExpandoObject实例都需要GetFullName方法,用扩展方法会更高效,不需要给每个实例单独绑定方法:
public static class ExpandoExtensions { public static string GetFullName(this ExpandoObject expando) { var properties = (IDictionary<string, object>)expando; if (properties.TryGetValue("FirstName", out var firstName) && properties.TryGetValue("LastName", out var lastName)) { return $"{firstName} {lastName}"; } return string.Empty; // 或者根据需求抛出异常 } } // 使用起来很简单: dynamic obj = new ExpandoObject(); obj.FirstName = "John"; obj.LastName = "Doe"; string fullName = obj.GetFullName();
3. 自定义动态对象(改用DynamicObject)
如果你的场景需要更复杂的动态行为,而不只是临时加属性和方法,可以继承DynamicObject实现自己的动态类型,这样就能在方法里直接访问实例的属性:
public class Person : DynamicObject { public string FirstName { get; set; } public string LastName { get; set; } public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { if (binder.Name == "GetFullName" && args.Length == 0) { result = $"{FirstName} {LastName}"; return true; } return base.TryInvokeMember(binder, args, out result); } } // 使用方式: dynamic obj = new Person(); obj.FirstName = "John"; obj.LastName = "Doe"; string fullName = obj.GetFullName();
关于你原始的写法
其实你的原始写法是最简洁的,特别适合单个临时动态对象的场景。闭包捕获obj在这个场景下几乎不会有问题——除非你后续会把obj重新赋值为另一个对象,否则完全可以放心使用。
内容的提问来源于stack exchange,提问作者Arkadi
相关产品推荐
相关产品推荐

