我希望創建一個靈活的輔助函式來比較兩個值,如果它們不同則回傳 true,并且還將第一個值更新為等于第二個值。這就是我想出的:
bool UpdateHelper<T>(ref T originalProperty, T newProperty) =>
!Equals(originalProperty, newProperty) && (originalProperty = newProperty) is T _;
bool changes = false;
changes |= UpdateHelper(ref name, frmName.Text);
changes |= UpdateHelper(ref description, frmDescription.Text);
...
目標是在對數十個屬性執行此操作時,避免為每個屬性復制粘貼相同的 5 行代碼:
if (myModel.SomeProperty != someUserInput.Text)
{
myModel.SomeProperty = someUserInput.Text
changes = true
}
(特別是在看到有人復制粘貼并更新 if 陳述句部分但忘記更新分配之后!)
我上面的助手在大多數情況下都有效,但不幸的是,當我嘗試在屬性上使用它時,它崩潰了:
changes |= UpdateHelper(ref myModel.Name, frmName.Text);
changes |= UpdateHelper(ref myModel.Description, frmDescription.Text);
屬性訪問回傳臨時值。'ref' 引數必須是可賦值的變數、欄位或陣列元素
誰能想出一個對兩者都有效的解決方案?
我試著玩弄運算式,例如:
bool UpdateHelper<T>(Expression<Func<T>> originalProperty, T newProperty) =>
!Equals(originalProperty.Compile().Invoke(), newProperty) && (originalProperty.Body.??? = newProperty) is T _;
changes |= UpdateHelper(() => myModel.Name, frmName.Text);
changes |= UpdateHelper(() => myModel.Description, frmDescription.Text);
changes |= UpdateHelper(() => myModel.ChildObject.Name, frmChildName.Text);
但我覺得它會變成決議運算式樹的噩夢,特別是如果它需要處理訪問嵌套在幾層下面的屬性的特殊情況(如上面的最后一個例子)。
關于如何優雅地做到這一點的任何想法?
uj5u.com熱心網友回復:
運算式很慢,正如您在代碼中看到的,您需要為每個賦值編譯它們。如果您想同時支持這兩種情況,一種解決方案是為獲取和設定提供單獨的函式:
bool UpdateHelper<T>(Func<T> originalGet, Action<T> originalSet, T newProperty) => ...
你會這樣稱呼它(對于欄位和屬性):
changes |= UpdateHelper(() => name, val => name = val, frmName.Text);
請注意,最優雅的解決方案是從不撰寫它,而是使用模板編譯器 ( .tt) 或純源代碼生成器 ( ISourceGenerator/ IIncrementalGenerator) 將其源代碼生成。
uj5u.com熱心網友回復:
我想我已經解決了。這種運算式決議在處理例如屬性更改事件通知時相對常見。
bool UpdateHelper<T>(Expression<Func<T>> originalProperty, T newProperty)
{
if (Equals(originalProperty.Compile().DynamicInvoke(), newProperty))
return false;
if (originalProperty.Body is MemberExpression mex && mex.Member is PropertyInfo pi)
pi.SetValue(Expression.Lambda(mex.Expression).Compile().DynamicInvoke(), newProperty);
else
throw new ArgumentException("The originalProperty argument must be a property expression such as `() => someObject.SomeProperty`");
return true;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/372171.html
上一篇:如何填充LISTC#
下一篇:ASP.NETCore-System.InvalidOperationException:嘗試激活時無法決議型別服務
