首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

跨命名空間物件屬性自動映射:ObjectMapper 基於反射的同名同型複製器

     編輯:關於ASP.NET

不同命名空間/程式集下擁有相同屬性名稱、型別的類別(如 DTO 與 Entity、Web Service 代理類與領域模型),需頻繁互轉。本文實作通用 ObjectMapper,基於反射自動匹配可讀/可寫同名同型屬性,消除手工賦值樣板代碼。

核心實現

public static class ObjectMapper {
    // 屬性映射描述
    public class PropertyMapper {
        public PropertyInfo SourceProperty { get; set; }
        public PropertyInfo TargetProperty { get; set; }
    }

    // 獲取可映射屬性對:同名、可讀/可寫、型別完全一致
    public static IList<PropertyMapper> GetMapperProperties(Type sourceType, Type targetType) {
        var srcProps = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        var tgtProps = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
        return (from s in srcProps
                join t in tgtProps on s.Name equals t.Name
                where s.CanRead && t.CanWrite && s.PropertyType == t.PropertyType
                select new PropertyMapper { SourceProperty = s, TargetProperty = t }).ToList();
    }

    // 執行複製
    public static void CopyProperties(object source, object target) {
        if (source == null || target == null) return;
        var mappers = GetMapperProperties(source.GetType(), target.GetType());
        foreach (var m in mappers) {
            var value = m.SourceProperty.GetValue(source);
            m.TargetProperty.SetValue(target, value);
        }
    }
}

使用範例

// 來源:Web Service 代理類
var dto = new Jasen.Core.Test.Info { Id = 1, Name = "Test", Amount = 100.5m, Created = DateTime.Now };

// 目標:領域模型
var entity = new Jasen.Core.Info();
ObjectMapper.CopyProperties(dto, entity);
// entity.Id=1, entity.Name="Test", entity.Amount=100.5m, entity.Created=DateTime.Now

進階擴展:支援映射規則自定義

// 1. 屬性名稱映射 Attribute
[AttributeUsage(AttributeTargets.Property)]
public class MapFromAttribute : Attribute { public string SourceName { get; set; } }

// 2. 型別轉換器
public interface IValueConverter {
    object Convert(object value, Type targetType);
}
public class DateTimeToStringConverter : IValueConverter {
    public object Convert(object value, Type targetType) 
        => value is DateTime dt ? dt.ToString("yyyy-MM-dd") : value;
}

// 3. 擴展 GetMapperProperties 讀取 Attribute、註冊 Converter

效能優化:緩存映射關係

private static readonly ConcurrentDictionary<Tuple<Type, Type>, IList<PropertyMapper>> _cache 
    = new ConcurrentDictionary<Tuple<Type, Type>, IList<PropertyMapper>>();

public static IList<PropertyMapper> GetMapperPropertiesCached(Type source, Type target) 
    => _cache.GetOrAdd(Tuple.Create(source, target), _ => GetMapperProperties(source, target));

對比主流映射庫

庫特點適用場景
AutoMapper慣例配置、Profile、投影、條件映射、單元測試友善複雜領域模型、DTO 多層轉換、團隊標準化
Mapster編譯時生成代碼、極高效能、零反射高頻映射、效能敏感、.NET Core 專案
ExpressMapperExpression Tree 編譯、輕量、支援巢狀映射中型專案、需自定義邏輯
本文 ObjectMapper零依賴、極簡、同名同型直映、易理解擴展輕量專案、臨時遷移、教學演示、禁止引入 NuGet 環境

避坑指南

  • 型別必須完全一致:`int` ↔ `long`、`decimal` ↔ `double` 皆不匹配,需擴展型別兼容邏輯或轉換器。
  • 唯讀屬性/私有 setter:`CanWrite` 為 false 將跳過,若需寫入請用 `BindingFlags.NonPublic` 或構造函數注入。
  • 巢狀物件:僅淺拷貝引用,深拷貝需遞迴調用或序列化反序列化。
  • 循環引用:映射雙向導航屬性會無限遞迴,需記錄已訪問物件集合。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved