Можно ли выполнить рефакторинг Expression <Func <T, object >> и destination.x = source.x? - PullRequest
0 голосов
/ 23 декабря 2009

Я создаю интерфейс для конкретной реализации копировального устройства. Последующим шагом будет определение того, смогу ли я легко добавить различные варианты поведения в зависимости от запрошенного типа копии (прямое копирование, или попытка, или try-catch-addToValidationDictionary). Это основной, который мне нужен / над которым я работаю - это try-catch-addToValidationDictionary. Было бы неплохо, если бы сами операторы копирования (result.AssetTag = asset.AssetTag) можно было повторно использовать в виде списка для другого потребителя, который не нуждается в функции try / catch / validation.

Общая форма такова:

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;
 }
}

Я пытаюсь выделить некоторые повторения с помощью лямбд, но пост Member.Name<IAmAnAsset>(lIAmAnAsset => lIAmAnAsset.AssetTag) из этого , кажется, занимает всего Expression<Func<T,object>>, и я не уверен, как вы бы использовали Выражение> перегрузка.

Одна попытка была следующей:

 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.Name<IAmAnAsset>(z=>z.AddedBy),()=>result.AddedBy=asset.AddedBy}, по любому из следующих критериев:

  • нужен IAmAnAsset.AddedBy в 2 местах в каждой строке
  • нужно. Добавлено 3 раза на одной строке
  • Member.Name<IAmAnAsset> на каждой строке
    • Возможно ли использовать это выражение для получения либо имени строки, либо значения ее оценки?

1 Ответ

0 голосов
/ 23 декабря 2009

Как насчет простой функции?

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...