首页 > 解决方案 > 重构类似的方法,但具有不同的返回类型

问题描述

我有两种方法:

public ActionResult<IEnumerable<IDataObject>> GetRelatedObjects([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName)
{
  if (string.IsNullOrWhiteSpace(primaryKey))
  {
    return BadRequest("Primary key cannot be empty.");
  }

  if (!TryGetClass(className, out var metaClass))
  {
    return NotFound($"Class [{className}] does not exist.");
  }

  if (!metaClass.Properties.TryGetValue(relationName, out var property))
  {
    return NotFound($"Class [{metaClass}] does not contain property [{relationName}].");
  }

  if (!(property is IMetaRelation relation))
  {
    return BadRequest($"Property [{relationName}] is not a relation.");
  }

  if (relation.Target.Cardinality != MetaCardinality.Multiple)
  {
    return BadRequest(`$"Relation [{relationName}] has multiple cardinality."`);
  }

  if (!_primaryKeyHandler.TryParsePrimaryKey(metaClass, primaryKey, out var primaryKeyValues))
  {
    return BadRequest("Cannot convert the primaryKey to the correct type.");
  }

  if (!_dataCalculator.SupportsData(metaClass))
  {
    return BadRequest($"The class [{className}] is not persisted");
  }

  var metaObject = _dataAccess.GetObject<IDataObject>(DataSession, metaClass, primaryKeyValues);
  if (metaObject == null)
  {

    return NotFound($"The metaObject for the primaryKey [{primaryKey}] nad the class [{className}] cannot be empty.");
  }





  // The validations above are the same as for GetRelatedObject()




  try
  {
    var list = _dataAccess.GetRelatedList<IDataObject>(DataSession, metaClass, primaryKeyValues, relation);

    return new ActionResult<IEnumerable<IDataObject>>(list);
  }
  catch (InvalidAuthorizationException)
  {
    return Unauthorized();
  }
}

第二个:

public ActionResult<IDataObject> GetRelatedObject([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName)
{
  if (string.IsNullOrWhiteSpace(primaryKey))
  {
    return BadRequest("Primary key cannot be empty.");
  }

  if (!TryGetClass(className, out var metaClass))
  {
    return NotFound($"Class [{className}] does not exist.");
  }

  if (!metaClass.Properties.TryGetValue(relationName, out var property))
  {
    return NotFound($"Class [{metaClass}] does not contain property [{relationName}].");
  }

  if (!(property is IMetaRelation relation))
  {
    return BadRequest($"Property [{relationName}] is not a relation.");
  }

  if (relation.Target.Cardinality == MetaCardinality.Multiple)
  {
    return BadRequest($"Relation [{relationName}] has multiple cardinality.");
  }

  if (!_primaryKeyHandler.TryParsePrimaryKey(metaClass, primaryKey, out var primaryKeyValues))
  {
    return BadRequest("Cannot convert the primaryKey to the correct type.");
  }

  if (!_dataCalculator.SupportsData(metaClass))
  {
    return BadRequest($"The class [{className}] is not persisted");
  }

  var metaObject = _dataAccess.GetObject<IDataObject>(DataSession, metaClass, primaryKeyValues);
  if (metaObject == null)
  {
    return NotFound($"The metaObject for the primaryKey [{primaryKey}] nad the class [{className}] cannot be empty.");
  }



  // The validations above are the same as for GetRelatedObjects()


  try
  {
    var relationValue = metaObject.GetObject<IDataObject>(relation);

    return new ActionResult<IDataObject>(relationValue);
  }
  catch (InvalidAuthorizationException)
  {
    return Unauthorized();
  }
}

正如代码中的注释所标记的那样,两种方法的验证都是相同的。在这两种方法中,都有一小部分代码不一样。两种方法的返回类型也不同。

我正在尝试将方法内部的验证重构为一个单独的方法。

这是我的尝试:

private void RelatedObject(string className, string primaryKey, string relationName, out IMetaRelation metaRelation, out IDataObject metaObject, out ActionResult<IDataObject> actionResult, out IDictionary<IMetaProperty, object> primaryKeyValues, out IMetaClass metaClass)
    {
      actionResult = null;
      metaRelation = null;

      if (string.IsNullOrWhiteSpace(primaryKey))
      {
        actionResult = BadRequest("Primary key cannot be empty.");
      }

      if (!TryGetClass(className, out metaClass))
      {
        actionResult = NotFound($"Class [{className}] does not exist.");
      }

      if (!metaClass.Properties.TryGetValue(relationName, out var property))
      {
        actionResult = NotFound($"Class [{metaClass}] does not contain property [{relationName}].");
      }

      if (!(property is IMetaRelation relation))
      {
        actionResult = BadRequest($"Property [{relationName}] is not a relation.");
      }

      if (relation.Target.Cardinality == MetaCardinality.Multiple)
      {
        actionResult = BadRequest($"Relation [{relationName}] has multiple cardinality.");
      }

      if (!_primaryKeyHandler.TryParsePrimaryKey(metaClass, primaryKey, out primaryKeyValues))
      {
        actionResult = BadRequest("Cannot convert the primaryKey to the correct type.");
      }

      if (!_dataCalculator.SupportsData(metaClass))
      {
        actionResult = BadRequest($"The class [{className}] is not persisted");
      }

      metaObject = _dataAccess.GetObject<IDataObject>(DataSession, metaClass, primaryKeyValues);
      if (metaObject == null)
      {
        actionResult = NotFound($"The metaObject for the primaryKey [{primaryKey}] nad the class [{className}] cannot be empty.");
      }
    }

这是 GetRelatedObject 内部的调用:

public ActionResult<IDataObject> GetRelatedObject([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName)
{
  RelatedObject(className, primaryKey, relationName, out var relation, out var metaObject, out var actionResult, out var primaryKeyValues, out var metaClass);
  if (actionResult != null)
  {
    return actionResult;
  }

  try
  {
    var relationValue = metaObject.GetObject<IDataObject>(relation);

    return new ActionResult<IDataObject>(relationValue);
  }
  catch (InvalidAuthorizationException)
  {
    return Unauthorized();
  }
}

这是 GetRelatedObjects 内部的调用:

public ActionResult<IEnumerable<IDataObject>> GetRelatedObjects([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName)
    {
      RelatedObject(className, primaryKey, relationName, out var relation, out var metaObject, out var actionResult, out var primaryKeyValues, out var metaClass);
      if (actionResult != null)
      {
        return actionResult;
      }

      try
      {
        var list = _dataAccess.GetRelatedList<IDataObject>(DataSession, metaClass, primaryKeyValues, relation);

        return new ActionResult<IEnumerable<IDataObject>>(list);
      }
      catch (InvalidAuthorizationException)
      {
        return Unauthorized();
      }
    }

我的尝试存在多个问题:

  1. GetRelatedObjects 和 GetRelatedObject 有不同的返回类型,我重构的方法只能支持一种
  2. 一些out变量没有使用GetRelatedObject而是使用GetRelatedObjects并反转

需要哪些更改来改进我的解决方案以便我可以摆脱我的问题?

标签: c#.netrestapi

解决方案


您已经在代码中声明每种方法的验证都是相同的......但它们不是。

从 GetRelatedObject:

if (relation.Target.Cardinality == MetaCardinality.Multiple)
{
    return BadRequest($"Relation [{relationName}] has multiple cardinality.");
}

来自 GetRelatedObjects:

if (relation.Target.Cardinality != MetaCardinality.Multiple)
{
    return BadRequest("The cardinality is not multiple");
}

话虽如此,我会做这样的事情并将验证合并到一个方法中以减少代码重复,添加一个参数以在多个/单个基数之间切换。

未经测试,所以我不知道它是否真的有效;)

public ActionResult<IDataObject> GetRelatedObject([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName)
{
    var validationError = ValidateRequest(className, primaryKey, relationName, allowMultipleCardinality: false);
    if (validationError) return validationError;

    try
    {
        var relationValue = metaObject.GetObject<IDataObject>(relation);
        return new ActionResult<IDataObject>(relationValue);
    }
    catch (InvalidAuthorizationException)
    {
        return Unauthorized();
    }
}

public ActionResult<IEnumerable<IDataObject>> GetRelatedObjects([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName)
{
    var validationError = ValidateRequest(className, primaryKey, relationName, allowMultipleCardinality: true);
    if (validationError) return validationError;

    try
    {
        var list = _dataAccess.GetRelatedList<IDataObject>(DataSession, metaClass, primaryKeyValues, relation);

        return new ActionResult<IEnumerable<IDataObject>>(list);
    }
    catch (InvalidAuthorizationException)
    {
        return Unauthorized();
    }
}

private ActionResult ValidateRequest([CanBeNull] string className, [CanBeNull] string primaryKey, [CanBeNull] string relationName, bool allowMultipleCardinality)
{
    if (string.IsNullOrWhiteSpace(primaryKey))
    {
        return BadRequest("Primary key cannot be empty.");
    }

    if (!TryGetClass(className, out var metaClass))
    {
        return NotFound($"Class [{className}] does not exist.");
    }

    if (!metaClass.Properties.TryGetValue(relationName, out var property))
    {
        return NotFound($"Class [{metaClass}] does not contain property [{relationName}].");
    }

    if (!(property is IMetaRelation relation))
    {
        return BadRequest($"Property [{relationName}] is not a relation.");
    }

    if (AllowMultipleCardinality)
    {
        if (relation.Target.Cardinality != MetaCardinality.Multiple)
        {
            return BadRequest("The cardinality is not multiple");
        }
    }
    else
    {
        if (relation.Target.Cardinality == MetaCardinality.Multiple)
        {
            return BadRequest($"Relation [{relationName}] has multiple cardinality.");
        }
    }

    if (!_primaryKeyHandler.TryParsePrimaryKey(metaClass, primaryKey, out var primaryKeyValues))
    {
        return BadRequest("Cannot convert the primaryKey to the correct type.");
    }

    if (!_dataCalculator.SupportsData(metaClass))
    {
        return BadRequest($"The class [{className}] is not persisted");
    }

    var metaObject = _dataAccess.GetObject<IDataObject>(DataSession, metaClass, primaryKeyValues);
    if (metaObject == null)
    {
        return NotFound($"The metaObject for the primaryKey [{primaryKey}] nad the class [{className}] cannot be empty.");
    }
}

推荐阅读