C# 表达式和destination.x=source.x是否可以重构?
我正在生成一个到具体实现copier的接口。后面的步骤是确定是否可以根据请求的复制类型轻松添加不同的行为直接复制,或尝试,或尝试捕获addToValidationDictionary。这是我需要/正在处理的主要问题,是try-catch-addToValidationDictionary。如果copy语句themselvesresult.AssetTag=asset.AssetTag以列表形式可供另一个不需要try/catch/validation功能的消费者重用,那就太好了 一般形式如下:C# 表达式和destination.x=source.x是否可以重构?,c#,lambda,C#,Lambda,我正在生成一个到具体实现copier的接口。后面的步骤是确定是否可以根据请求的复制类型轻松添加不同的行为直接复制,或尝试,或尝试捕获addToValidationDictionary。这是我需要/正在处理的主要问题,是try-catch-addToValidationDictionary。如果copy语句themselvesresult.AssetTag=asset.AssetTag以列表形式可供另一个不需要try/catch/validation功能的消费者重用,那就太好了 一般形式如下: p
public static AssetService
{
public static ModelAsset CreateAssetDomain(IAmAnAsset asset, IValidationDictionary validationDictionary)
{
var result=new ModelAsset();
var hasExceptions=false;
try
{
result.AssetTag = asset.AssetTag;
}
catch (System.Exception exception)
{
validationDictionary.AddError(Member.Name<IAmAnAsset>(lIAmAnAsset => lIAmAnAsset.AssetTag), exception.Message);
hasExceptions = true;
}
try
{
result.LocationIdentifer = asset.LocationIdentifer;
}
catch (System.Exception exception)
{
validationDictionary.AddError(Member.Name<IAmAnAsset>(lIAmAnAsset => lIAmAnAsset.LocationIdentifer), exception.Message);
hasExceptions = true;
}
...
if (hasExceptions)
throw new ArgumentException("Failed validation");
return result;
}
}
我试图排除lambdas的一些重复,但是post中的Member.NamelIAmAnAsset=>lIAmAnAsset.AssetTag似乎只接受一个表达式,我不确定如何使用表达式>重载
一次尝试如下:
Action<Action, Expression<Func<IAmAnAsset, object>>> CopyActions = (copyAction, expression) =>
{
try
{
copyAction();
}
catch (Exception exception)
{
validationDictionary.AddError(Member.Name<IAmAnAsset>(expression), exception.Message);
hasExceptions = true;
}
};
var copyActions = new Dictionary<string,Action>()
{
Member.Name<IAmAnAsset>(z=>z.AddedBy),()=>result.AddedBy=asset.AddedBy},
Member.Name<IAmAnAsset>(z=>z.AssetTag),()=>result.AssetTag=asset.AssetTag},
...
}
foreach (var item in copyActions)
{
tryCopyAction(item.Value, item.Key);
}
if (hasExceptions)
throw new ArgumentException("Failed validation");
return result;
我希望能找到一个解决方案,减少系统固有的重复
Member.Namez=>z.AddedBy,=>result.AddedBy=asset.AddedBy},
根据以下任一标准:
需要IAMANASET.ADEDBY在每行的2个位置
需要。在同一行上添加3次
每个行上的成员名称
是否可以使用此表达式来检索字符串名称或对其求值的值?
一个简单的函数怎么样
public static class Member
{
private static string GetMemberName(Expression expression)
{
switch (expression.NodeType)
{
case ExpressionType.MemberAccess: var memberExpression = (MemberExpression)expression; var supername = GetMemberName(memberExpression.Expression); if (String.IsNullOrEmpty(supername)) return memberExpression.Member.Name; return String.Concat(supername, '.', memberExpression.Member.Name);
case ExpressionType.Call: var callExpression = (MethodCallExpression)expression; return callExpression.Method.Name;
case ExpressionType.Convert: var unaryExpression = (UnaryExpression)expression; return GetMemberName(unaryExpression.Operand);
case ExpressionType.Parameter: return String.Empty;
default: throw new ArgumentException("The expression is not a member access or method call expression");
}
}
public static string Name<T,V>(Expression<Func<T, V>> expression)
{
return GetMemberName(expression.Body);
}
public static string Name<T>(Expression<Action<T>> expression)
{
return GetMemberName(expression.Body);
}
}
void Copy<D, S, V>(D dest, S source, Expression<Func<S, V>> getVal, Action<D, V> setVal, IDictionary validationDictionary)
{
Func<S, V> doGetVal = getVal.Compile();
try { setVal(dest, (V)doGetVal(source)); }
catch (System.Exception exception)
{
validationDictionary.Add(Member.Name<S,V>(getVal), exception.Message);
}
}
class TestAsset { public string AssetTag { get; set; } public string LocationIdentifier { get; set; } }
TestAsset Test()
{
Dictionary<string, string> validationDictionary = new Dictionary<string, string>();
var result = new TestAsset{ AssetTag = "a", LocationIdentifier = "b" };
var asset = new TestAsset{ AssetTag = "A", LocationIdentifier = "B" };
var validationCount = validationDictionary.Count();
Copy(result, asset, x => asset.AssetTag, (x, v) => x.AssetTag = v, validationDictionary);
Copy(result, asset, x => asset.LocationIdentifier, (x, v) => x.LocationIdentifier = v, validationDictionary);
if (validationCount < validationDictionary.Count) throw new ArgumentException("Failed validation");
return result;
}
Name是实现编译时属性名安全的一种方法。因此,我没有使用字符串文字AssetTag,而是使用了一个lambda表达式,利用该属性可以检索字符串,而无需反射,或者检索容易出现错误的字符串文字。此外,您的函数不考虑所传递的Member.Name参数的差异,这使得使用更加丑陋。操作不返回任何内容,因此不能用于SetVal。由于该参数将返回不同的类型,另一个类型参数将使用法更难看,也不太可能是可推断的。我已修复了函数声明,并对避免反射和字符串文字的不同方式进行了注释。常量无法避免属性被重命名和引入细微错误的问题,Lambda表达式方法是编译时安全的。此外,这将需要为每个类上的每个属性添加常量,该功能将用于。我已经用测试时有效的代码重写了答案。