方案一:粗糙但可用
?
var changes = new List<string>();void CompareAndAddChange<T>(string propertyName, T oldValue, T newValue, Func<T, string> descriptionFunc = null)
{if (!EqualityComparer<T>.Default.Equals(oldValue, newValue)){var oldValueStr = descriptionFunc != null ? descriptionFunc(oldValue) : oldValue.ToString();var newValueStr = descriptionFunc != null ? descriptionFunc(newValue) : newValue.ToString();changes.Add($"{propertyName}: [{oldValueStr}] => [{newValueStr}]");}
}CompareAndAddChange("公司名稱", cusOld.CompanyName, modelDto.CompanyName);
CompareAndAddChange("公司類型", cusOld.CompanyType, modelDto.CompanyType, x => x.GetDescription());
CompareAndAddChange("公司代碼", cusOld.CompanyCode, modelDto.CompanyCode);
CompareAndAddChange("公司介紹", cusOld.Contents, modelDto.Contents);
CompareAndAddChange("會員等級", cusOld.MemberLevel, modelDto.MemberLevel, x => x.GetDescription());
CompareAndAddChange("會員類型", cusOld.MemberType, modelDto.MemberType, x => x.GetDescription());
CompareAndAddChange("業務員", cusOld.SaleId, modelDto.SaleId, async id =>
{var user = await _userRepository.GetWhereAsync(x => x.Id == id);return user?.NickName ?? id.ToString();
});
CompareAndAddChange("點數", cusOld.Ratio, modelDto.Ratio);
CompareAndAddChange("聯系方式", cusOld.Phone, modelDto.Phone);
CompareAndAddChange("會員有效期", cusOld.MemberValidityPeriod, modelDto.MemberValidityPeriod);
CompareAndAddChange("最大API客戶數", cusOld.MaxApiCusCount, modelDto.MaxApiCusCount);
CompareAndAddChange("最大渠道數", cusOld.MaxChannelCount, modelDto.MaxChannelCount);
CompareAndAddChange("最大供應商數", cusOld.MaxSupplierCount, modelDto.MaxSupplierCount);
CompareAndAddChange("備注", cusOld.Remark, modelDto.Remark);var content = string.Join(",", changes);
這種優化方式做了以下改進:
-
單一函數處理比較和改變的添加:使用泛型方法
CompareAndAddChange
來處理每個屬性的比較和變更添加,避免了重復的邏輯。 -
異步處理:在需要獲取業務員信息時,通過異步方法從
_userRepository
中獲取用戶信息。 -
描述函數:對于特定屬性(如枚舉類型),提供了描述函數,用于獲取更具描述性的字符串,提高了可讀性。
這種方法不僅減少了代碼量,還提高了可維護性和可擴展性,使得未來對屬性的改動更易于處理和擴展。
方案二:優化更舒服、反射
var changes = new List<string>();// 獲取所有屬性
var properties = typeof(ModelDto).GetProperties();foreach (var property in properties)
{// 獲取屬性值var oldValue = property.GetValue(cusOld);var newValue = property.GetValue(modelDto);// 如果新舊值不相等if (!Equals(oldValue, newValue)){// 特殊處理 SaleId 屬性if (property.Name == "SaleId"){var userNew = await _userRepository.GetWhereAsync(x => x.Id == (int)newValue);var userOld = await _userRepository.GetWhereAsync(x => x.Id == (int)oldValue);changes.Add($"業務員: [{userOld?.NickName}] => [{userNew?.NickName}]");}else{changes.Add($"{property.Name}: [{oldValue}] => [{newValue}]");}}
}var content = string.Join(",", changes);
這種方法的優點包括:
-
自動化屬性比較:利用反射獲取
ModelDto
的所有屬性,并比較舊值和新值。 -
特殊處理:對于特定屬性(如
SaleId
),可以根據需要進行特殊處理,例如異步獲取用戶信息。 -
簡化代碼:避免了手動編寫每個屬性的比較邏輯,使代碼更加簡潔和易于維護。
-
可擴展性:如果需要比較的屬性增加或者需要額外的特殊處理,只需在相應的位置添加邏輯即可。
這種方法適合于需要自動化處理屬性比較和生成變更日志的場景,能夠有效地提高代碼的復用性和可維護性。
方案三:進階加描述
如果你想要在使用反射時獲取屬性的自定義備注或描述,你可以借助 C# 中的自定義屬性來實現。以下是一個簡單的示例,展示如何定義一個自定義屬性,并在反射時使用它獲取字段的備注:
首先,定義一個自定義屬性類 FieldDescriptionAttribute
:
[AttributeUsage(AttributeTargets.Property)]
public class FieldDescriptionAttribute : Attribute
{public string Description { get; }public FieldDescriptionAttribute(string description){Description = description;}
}
然后,在你的 ModelDto
類中使用這個自定義屬性:
public class ModelDto
{[FieldDescription("公司名稱")]public string CompanyName { get; set; }[FieldDescription("公司類型")]public CompanyType CompanyType { get; set; }[FieldDescription("公司代碼")]public string CompanyCode { get; set; }// 其他屬性省略
}
接下來,在生成變更內容時,使用這些自定義屬性來獲取字段的備注:
var changes = new List<string>();var properties = typeof(ModelDto).GetProperties();foreach (var property in properties)
{var oldValue = property.GetValue(cusOld);var newValue = property.GetValue(modelDto);if (!Equals(oldValue, newValue)){// 獲取屬性上的 FieldDescriptionAttributevar descriptionAttribute = (FieldDescriptionAttribute)property.GetCustomAttributes(typeof(FieldDescriptionAttribute), false).FirstOrDefault();// 如果找到了 FieldDescriptionAttribute,則使用其描述,否則使用屬性名var propertyName = descriptionAttribute != null ? descriptionAttribute.Description : property.Name;// 特殊處理 SaleId 屬性if (property.Name == "SaleId"){var userNew = await _userRepository.GetWhereAsync(x => x.Id == (int)newValue);var userOld = await _userRepository.GetWhereAsync(x => x.Id == (int)oldValue);changes.Add($"{propertyName}: [{userOld?.NickName}] => [{userNew?.NickName}]");}else{changes.Add($"{propertyName}: [{oldValue}] => [{newValue}]");}}
}var content = string.Join(",", changes);
在上面的示例中,FieldDescriptionAttribute
允許你為每個屬性指定一個自定義的描述。在遍歷屬性時,使用 GetCustomAttributes
方法獲取屬性上的自定義屬性,并從中獲取描述信息,以替代默認的屬性名作為變更內容的一部分。
這種方法能夠使你的代碼更具可讀性和可維護性,特別是在處理需要詳細描述的屬性時。
方案四:獲取summary備注
/// <summary>
/// 備注
/// </summary>
如果你希望在生成變更內容時,使用屬性的 XML 注釋(summary),或者自定義的備注信息作為字段的描述,可以結合使用反射和 XML 注釋讀取來實現。以下是一個示例:
首先,假設你的 ModelDto
類定義如下:
public class ModelDto
{/// <summary>/// 公司名稱/// </summary>public string CompanyName { get; set; }/// <summary>/// 公司類型/// </summary>public CompanyType CompanyType { get; set; }/// <summary>/// 公司代碼/// </summary>public string CompanyCode { get; set; }// 其他屬性省略
}
然后,可以編寫一個方法來獲取屬性的備注信息,優先使用 XML 注釋(summary),如果沒有 XML 注釋則使用自定義的備注信息:
public static string GetPropertyDescription(PropertyInfo property)
{// 嘗試獲取 XML 注釋(summary)var xmlComment = property.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false).FirstOrDefault() as System.ComponentModel.DescriptionAttribute;if (xmlComment != null){return xmlComment.Description;}// 如果沒有 XML 注釋,則使用屬性名作為備注return property.Name;
}
最后,根據這個方法來生成變更內容:
var changes = new List<string>();var properties = typeof(ModelDto).GetProperties();foreach (var property in properties)
{var oldValue = property.GetValue(cusOld);var newValue = property.GetValue(modelDto);if (!Equals(oldValue, newValue)){var propertyName = GetPropertyDescription(property);// 特殊處理 SaleId 屬性if (property.Name == "SaleId"){var userNew = await _userRepository.GetWhereAsync(x => x.Id == (int)newValue);var userOld = await _userRepository.GetWhereAsync(x => x.Id == (int)oldValue);changes.Add($"{propertyName}: [{userOld?.NickName}] => [{userNew?.NickName}]");}else{changes.Add($"{propertyName}: [{oldValue}] => [{newValue}]");}}
}var content = string.Join(",", changes);
在上面的示例中,GetPropertyDescription
方法會嘗試從 XML 注釋(summary)中獲取屬性的描述信息,如果找不到 XML 注釋,則默認使用屬性的名稱。這樣可以根據屬性的描述信息生成更具描述性的變更內容。
這種方法結合了反射和 XML 注釋讀取,能夠使你的代碼更加靈活和可維護,特別是在需要生成詳細變更日志或報告時非常有用。