Skip to content

Commit

Permalink
Merge pull request #13 from maxzh1999tw/delegates
Browse files Browse the repository at this point in the history
將所有 Func<> 接口改為委派
  • Loading branch information
maxzh1999tw committed Jan 15, 2024
2 parents 8ac5f59 + 463f424 commit ceddc7f
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 47 deletions.
8 changes: 4 additions & 4 deletions Excely.UnitTests/ClassListTableConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public void ConvertFromErrorData_ShouldThrowExceptions()
});
var options = new ClassListTableConverterOptions<SimpleClass>
{
StopWhenError = false,
ThrowWhenError = false,
};
var converter = new ClassListTableConverter<SimpleClass>();

Expand All @@ -323,7 +323,7 @@ public void ConvertFromErrorData_ShouldRecordErrorAndReturnListWithoutErrorRecor
var errors = new Dictionary<CellLocation, Exception>();
var options = new ClassListTableConverterOptions<SimpleClass>
{
StopWhenError = false,
ThrowWhenError = false,
ErrorHandlingPolicy = (location, obj, p, value, err) =>
{
errors.Add(location, err);
Expand Down Expand Up @@ -363,7 +363,7 @@ public void ConvertFromErrorData_ShouldReturnCorrectListWithoutErrorRecords()
});
var options = new ClassListTableConverterOptions<SimpleClass>
{
StopWhenError = false,
ThrowWhenError = false,
};
var converter = new ClassListTableConverter<SimpleClass>(options);

Expand Down Expand Up @@ -397,7 +397,7 @@ public void ConvertFromErrorData_ShouldReturnListWithFixedData()
var errors = new Dictionary<CellLocation, Exception>();
var options = new ClassListTableConverterOptions<SimpleNullableClass>
{
StopWhenError = false,
ThrowWhenError = false,
ErrorHandlingPolicy = (location, obj, p, value, err) =>
{
p.SetValue(obj, null);
Expand Down
70 changes: 54 additions & 16 deletions Excely/TableConverters/ClassListTableConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ private IEnumerable<TClass> ImportInternal(ExcelyTable table, Func<PropertyInfo,
var errorFixed = Options.ErrorHandlingPolicy(new CellLocation(rowIndex, columnIndex), obj, property, value, ex);

// 錯誤處理失敗,且要求停止
if (!errorFixed && Options.StopWhenError)
if (!errorFixed && Options.ThrowWhenError)
{
throw;
}
Expand Down Expand Up @@ -172,40 +172,78 @@ public class ClassListTableConverterOptions<TClass>
/// 當轉換發生錯誤時是否立刻停止。
/// 若此欄為 false,則發生錯誤時會跳過該 Row,繼續執行匯入。
/// </summary>
public bool StopWhenError { get; set; } = true;
public bool ThrowWhenError { get; set; } = true;

/// <summary>
/// 當寫入的值與目標型別不同時,是否自動嘗試轉換。
/// </summary>
public bool EnableAutoTypeConversion { get; set; } = true;

/// <summary>
/// 決定 Property 作為欄位時的名稱。
/// 輸入參數為 PropertyInfo,輸出結果為「欄位名稱」,
/// 預設為 Property.Name。
/// 預設為 PropertyInfo.Name
/// </summary>
public Func<PropertyInfo, string?> PropertyNamePolicy { get; set; } = prop => prop.Name;
public PropertyNamePolicyDelegate PropertyNamePolicy { get; set; } = property => property.Name;

/// <summary>
/// 決定 Property 出現在表頭時的位置。
/// 輸入參數為 (所有Properties, PropertyInfo),輸出結果為「欄位索引」,
/// 若該 Property 沒有出現在表頭中,請回傳 null。
/// 預設為依照 property 預設順序排序。
/// 取得 Property 出現在表頭時的位置。
/// 預設為依類別內預設排序。
/// </summary>
public Func<PropertyInfo[], PropertyInfo, int?> PropertyIndexPolicy { get; set; } = (props, prop) => Array.IndexOf(props, prop);
public PropertyIndexPolicyDelegate PropertyIndexPolicy { get; set; } = (propertys, property) => Array.IndexOf(propertys, property);

/// <summary>
/// 決定將值寫入至 Property 時應寫入的值。
/// 輸入參數為 (PropertyInfo, 原始值),輸出結果為「應寫入的值」。
/// 預設為原值。
/// </summary>
public Func<PropertyInfo, object?, object?> PropertyValueSettingPolicy { get; set; } = (prop, obj) => obj;
public PropertyValueSettingPolicyDelegate PropertyValueSettingPolicy { get; set; } = (prop, obj) => obj;

/// <summary>
/// 將值輸入進物件發生錯誤時,決定錯誤處理方式。
/// 輸入參數為 (儲存格座標, 目標物件, PropertyInfo, 嘗試輸入的值, 發生的錯誤),輸出結果為「錯誤是否得到修正」。
/// 預設為不處理錯誤。
/// </summary>
public Func<CellLocation, TClass, PropertyInfo, object?, Exception, bool> ErrorHandlingPolicy { get; set; } = (_, _, _, _, _) => false;
public ErrorHandlingPolicyDelegate ErrorHandlingPolicy { get; set; } = (_, _, _, _, _) => false;

#region ===== Policy delegates =====

/// <summary>
/// 當寫入的值與目標型別不同時,是否自動嘗試轉換
/// 取得 Property 作為欄位時的名稱
/// </summary>
public bool EnableAutoTypeConversion { get; set; } = true;
/// <param name="property">當前決定的 Property</param>
/// <returns>欄位名稱</returns>
public delegate string? PropertyNamePolicyDelegate(PropertyInfo property);

/// <summary>
/// 取得 Property 作為欄位時的位置。
/// </summary>
/// <param name="allProperties">目標類別的所有 Property</param>
/// <param name="property">當前決定的 Property</param>
/// <returns>欄位權重(越小越靠前),若回傳 null,代表此 Property 沒有對應的欄位</returns>
public delegate int? PropertyIndexPolicyDelegate(PropertyInfo[] allProperties, PropertyInfo property);

/// <summary>
/// 決定將值寫入至 Property 時應寫入的值。
/// </summary>
/// <param name="property">當前寫入欄位</param>
/// <param name="originalValue">原始讀取到的值</param>
/// <returns>欲寫入的值</returns>
public delegate object? PropertyValueSettingPolicyDelegate(PropertyInfo property, object? originalValue);

/// <summary>
/// 將值輸入進物件發生錯誤時,決定錯誤處理方式。
/// </summary>
/// <param name="cellLocation">發生錯誤的座標</param>
/// <param name="writtingObject">正在寫入的目標物件</param>
/// <param name="writtingProperty">正在寫入的目標 Property</param>
/// <param name="writtingValue">嘗試寫入的值</param>
/// <param name="exception">發生的錯誤</param>
/// <returns>錯誤是否得到修正</returns>
public delegate bool ErrorHandlingPolicyDelegate(
CellLocation cellLocation,
TClass writtingObject,
PropertyInfo writtingProperty,
object? writtingValue,
Exception exception);

#endregion ===== Policy delegates =====
}
}
32 changes: 26 additions & 6 deletions Excely/TableConverters/DictionaryListTableConverter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Excely.TableConverters
using System.Formats.Asn1;
using System.Reflection;

namespace Excely.TableConverters
{
/// <summary>
/// 將 Table 轉換為字典列表。
Expand Down Expand Up @@ -84,18 +87,35 @@ public class DictionaryListTableConverterOptions

/// <summary>
/// 決定欄位作為 Key 時的名稱。
/// 輸入參數為 (欄位index, 欄位名稱),輸出結果為 Key,
/// 若 HasSchema 為 false 時,欄位名稱將是 null。
/// 預設為 (欄位名稱 ?? 欄位index)。
/// 若 return null,代表此欄位不匯入。
/// </summary>
public Func<int, string?, string?> CustomKeyNamePolicy { get; set; } = (index, fieldName) => fieldName ?? index.ToString();
public CustomKeyNamePolicyDelegate CustomKeyNamePolicy { get; set; } = (index, fieldName) => fieldName ?? index.ToString();

/// <summary>
/// 決定將值寫入至 Vale 時應寫入的值。
/// 輸入參數為 (Key, 原始值),輸出結果為「應寫入的值」。
/// 預設為原值。
/// </summary>
public Func<string, object?, object?> CustomValuePolicy { get; set; } = (key, value) => value;
public CustomValuePolicyDelegate CustomValuePolicy { get; set; } = (key, value) => value;

#region ===== Policy delegates =====

/// <summary>
/// 決定欄位作為 Key 時的名稱。
/// </summary>
/// <param name="fieldIndex">欄位index</param>
/// <param name="fieldName">欄位名稱</param>
/// <returns>用作 key 的字串,若回傳 null,代表此欄位不匯入</returns>
public delegate string? CustomKeyNamePolicyDelegate(int fieldIndex, string? fieldName);

/// <summary>
/// 決定將值寫入至 Vale 時應寫入的值。
/// </summary>
/// <param name="key">代表此欄的 key 值</param>
/// <param name="originalValue">原始讀取到的值</param>
/// <returns>應寫入的值</returns>
public delegate object? CustomValuePolicyDelegate(string key, object? originalValue);

#endregion ===== Policy delegates =====
}
}
48 changes: 39 additions & 9 deletions Excely/TableFactories/ClassListTableFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,31 +85,61 @@ public class ClassListTableFactoryOptions<TClass>
public bool WithSchema { get; set; } = true;

/// <summary>
/// 決定 Property 是否應作為欄位匯出的執行邏輯。
/// 輸入參數為 PropertyInfo,輸出結果為「是否應作為欄位匯出」,
/// 決定 Property 是否應作為欄位匯出。
/// 預設為全部欄位都匯出。
/// </summary>
public Func<PropertyInfo, bool> PropertyShowPolicy { get; set; } = _ => true;
public PropertyShowPolicyDelegate PropertyShowPolicy { get; set; } = _ => true;

/// <summary>
/// 決定 Property 作為欄位時的名稱。
/// 輸入參數為 PropertyInfo,輸出結果為「欄位名稱」,
/// 預設為 PropertyInfo.Name。
/// </summary>
public Func<PropertyInfo, string?> PropertyNamePolicy { get; set; } = p => p.Name;
public PropertyNamePolicyDelegate PropertyNamePolicy { get; set; } = property => property.Name;

/// <summary>
/// 決定 Property 作為欄位時的順序。
/// 輸入參數為 (所有Properties, 當前PropertyInfo),輸出結果為「排序(由小到大)」,
/// 預設為依類別內預設排序。
/// </summary>
public Func<PropertyInfo[], PropertyInfo, int> PropertyOrderPolicy { get; set; } = (properties, p) => Array.IndexOf(properties, p);
public PropertyOrderPolicyDelegate PropertyOrderPolicy { get; set; } = (properties, property) => Array.IndexOf(properties, property);

/// <summary>
/// 決定資料寫入欄位時的值。
/// 輸入參數為 (PropertyInfo, 當前匯出物件),輸出結果為「欲寫入欄位的值」,
/// 預設為該 Property 之 Value。
/// </summary>
public Func<PropertyInfo, TClass, object?> CustomValuePolicy { get; set; } = (p, obj) => p.GetValue(obj);
public CustomValuePolicyDelegate CustomValuePolicy { get; set; } = (property, obj) => property.GetValue(obj);

#region ===== Policy delegates =====

/// <summary>
/// 決定 Property 是否應作為欄位匯出。
/// </summary>
/// <param name="property">當前決定的 Property</param>
/// <returns>是否應匯出</returns>
public delegate bool PropertyShowPolicyDelegate(PropertyInfo property);

/// <summary>
/// 決定 Property 作為欄位時的名稱。
/// </summary>
/// <param name="property">當前決定的 Property</param>
/// <returns>欄位名稱</returns>
public delegate string? PropertyNamePolicyDelegate(PropertyInfo property);

/// <summary>
/// 決定 Property 作為欄位時的順序。
/// </summary>
/// <param name="allProperties">目標類別的所有 Property</param>
/// <param name="property">當前決定的 Property</param>
/// <returns>欄位權重(越小越靠前)</returns>
public delegate int? PropertyOrderPolicyDelegate(PropertyInfo[] allProperties, PropertyInfo property);

/// <summary>
/// 決定資料寫入欄位時的值。
/// </summary>
/// <param name="property">當前決定的 Property</param>
/// <param name="obj">當前寫入的目標物件</param>
/// <returns>應寫入的值</returns>
public delegate object? CustomValuePolicyDelegate(PropertyInfo property, TClass obj);

#endregion ===== Policy delegates =====
}
}
57 changes: 45 additions & 12 deletions Excely/TableFactories/DictionaryListTableFactory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Excely.TableFactories
using System.Formats.Asn1;
using System.Reflection;

namespace Excely.TableFactories
{
/// <summary>
/// 提供以字典 Key 為欄位,將字典集合傾印至表格的功能。
Expand Down Expand Up @@ -74,31 +77,61 @@ public class DictionaryListTableFactoryOptions
public bool WithSchema { get; set; } = true;

/// <summary>
/// 決定 key 是否應作為欄位匯出的執行邏輯。
/// 輸入參數為 key,輸出結果為「是否應作為欄位匯出」,
/// 決定 key 是否應作為欄位匯出。
/// 預設為全部欄位都匯出。
/// </summary>
public Func<string, bool> KeyShowPolicy { get; set; } = _ => true;
public KeyShowPolicyDelegate KeyShowPolicy { get; set; } = _ => true;

/// <summary>
/// 決定 key 作為欄位時的名稱。
/// 輸入參數為 key,輸出結果為「欄位名稱」,
/// 預設為 key。
/// </summary>
public Func<string, string?> KeyNamePolicy { get; set; } = k => k;
public KeyNamePolicyDelegate KeyNamePolicy { get; set; } = key => key;

/// <summary>
/// 決定 key 作為欄位時的順序。
/// 輸入參數為 (所有key(預設排序), key),輸出結果為「排序(由小到大)」,
/// 預設為依 key 出現順序排序。
/// 決定 key 作為欄位時的權重(越小越靠前)。
/// 預設為 key 的預設順序。
/// </summary>
public Func<string[], string, int> KeyOrderPolicy { get; set; } = (keys, k) => Array.IndexOf(keys, k);
public KeyOrderPolicyDelegate KeyOrderPolicy { get; set; } = (allKeys, key) => Array.IndexOf(allKeys, key);

/// <summary>
/// 決定資料寫入欄位時的值。
/// 輸入參數為 (key, 當前匯出物件),輸出結果為「欲寫入欄位的值」,
/// 預設為 Value。
/// </summary>
public Func<string, Dictionary<string, object?>, object?> CustomValuePolicy { get; set; } = (k, dict) => dict.GetValueOrDefault(k, null);
public CustomValuePolicyDelegate CustomValuePolicy { get; set; } = (key, dict) => dict.GetValueOrDefault(key, null);

#region ===== Policy delegates =====

/// <summary>
/// 決定 key 是否應作為欄位匯出。
/// </summary>
/// <param name="key">當前決定的 key</param>
/// <returns>是否應匯出</returns>
public delegate bool KeyShowPolicyDelegate(string key);

/// <summary>
/// 決定 key 作為欄位時的名稱。
/// </summary>
/// <param name="key">當前決定的 key</param>
/// <returns>欄位名稱</returns>
public delegate string? KeyNamePolicyDelegate(string key);

/// <summary>
/// 決定 key 作為欄位時的權重(越小越靠前)。
/// </summary>
/// <param name="allKeys">所有 key</param>
/// <param name="key">當前決定的 key</param>
/// <returns>欄位權重</returns>
public delegate int KeyOrderPolicyDelegate(string[] allKeys, string key);

/// <summary>
/// 決定資料寫入欄位時的值。
/// </summary>
/// <param name="key">當前決定的 key</param>
/// <param name="writtingDict">當前正在寫入的 Dictionary</param>
/// <returns>應寫入的值</returns>
public delegate object? CustomValuePolicyDelegate(string key, Dictionary<string, object?> writtingDict);

#endregion ===== Policy delegates =====
}
}

0 comments on commit ceddc7f

Please sign in to comment.