ASP.NET Core 路由配置中常見匿名類型傳參:
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" });
這啟發了「突變賦值」想法:若 C# 支持 := 運算符,可一行完成多屬性賦值:
// 假想語法
form := new { Text = "Hello", Top = 100, Left = 200 };
// 等價於
form.Text = "Hello";
form.Top = 100;
form.Left = 200;
可惜 C# 無此運算符,也無語法宏。退而求其次:用擴展方法 + 反射模擬。
public static class Mutant
{
public static void MAssign(this object target, object source)
{
if (target == null || source == null) return;
var sourceProps = source.GetType().GetProperties()
.Where(p => p.CanRead);
foreach (var sp in sourceProps)
{
var tp = target.GetType().GetProperty(sp.Name, sp.PropertyType);
if (tp == null || !tp.CanWrite) continue;
var value = sp.GetValue(source);
tp.SetValue(target, value);
}
}
}
// 傳統繁瑣方式
form.Text = "Hello World";
form.Top = 100;
form.Left = 200;
// 一行搞定
form.MAssign(new { Text = "Hello World", Top = 100, Left = 200 });
| 問題 | 影響 | 解決方向 |
|---|---|---|
| 反射性能開銷 | 高頻調用有壓力 | 緩存 PropertyInfo、使用表達式樹編譯委托、IL Emit |
| 僅匹配同名同類型屬性 | 類型不兼容(如 int/long)失效 | 引入類型轉換器、AutoMapper 風格映射配置 |
| 無法處理字段、只讀屬性 | 覆蓋面不全 | 擴展 BindingFlags、支持私有 setter |
| 無驗證、無異常處理 | 靜默失敗難排查 | 返回映射結果、收集錯誤信息 |
// AutoMapper 配置
var config = new MapperConfiguration(cfg =>
cfg.CreateMap());
var mapper = config.CreateMapper();
var entity = mapper.Map(dto);
// Mapster(零配置、高性能)
var entity = dto.Adapt();
建議:簡單場景用 MAssign,複雜映射上成熟庫。
public static class AdvancedMutant
{
public static void DeepAssign(this object target, object source,
HashSet
「突變賦值」思想雖無語法支持,但擴展方法 + 反射 + 匿名類型組合實現了極具表達力的屬性批量賦值模式。理解其本質是運行期屬性名匹配複製,有助於在適當場景(配置映射、DTO 轉換、測試數據構建)靈活應用,複雜場景轉向成熟映射庫。