【问题标题】:Is it possible to use a delegate or generic for any void method?是否可以对任何 void 方法使用委托或泛型?
【发布时间】:2014-08-20 04:05:30
【问题描述】:

我正在尝试编写一个异常处理程序类,它将 EF 异常类型转换为 HttpStatusCodes。 我知道如何处理捕获并将消息发送到 ApiController。

public class ExceptionConverter : IExceptionConverter
{
    //need the parameter
    public HttpStatusCode Convert()
    {
        try
        {
            //call the void repository method here
        }
        catch (Exception exception)
        {
            if (exception is ObjectNotFoundException)
                return HttpStatusCode.NotFound;
            if (exception is InvalidOperationException)
                return HttpStatusCode.BadRequest;
        }
        return HttpStatusCode.OK;
    }
}

我想知道是否有办法编写可以调用我的 void 存储库方法的 Delagate 或 Generic 方法。

我在想我可以将接口与我在转换中使用的方法一起使用

public interface IHandleCrudOperations
{
    //All of these methods need to be able to take in many different parameters
    //They will always need a parameter though
    void Remove();
    void Add();
    void Edit();
    void Clone();
}

如您所见,我需要能够根据相关存储库方法传入大量不同的参数:

//userRepository
public void Remove(int userKey)
{
    //stuff
}

//groupRepository
public void Remove(string groupName)
{
    //stuff
}

//someOtherRepository
public void Remove(RemoveSomethingRequest request)
{
    //stuff
}

我考虑过为此使用通用方法:

public interface IHandleCrudOperations
{
    //All of these methods need to be able to take in many different parameters
    //They will always need a parameter though
    void Remove<T>(T item);
    void Add<T>(T item);
    void Edit<T>(T item);
    void Clone<T>(T item);
}

现在实施变得困难:

//userRepository
public void Remove<T>(T item)
{
    //SERIOUS code smell here
    var userKey = (int)(object)item
    _context.Users.FirstOrDefault(x => x.UserKey == userKey);
    //stuff
}

//groupRepository
public void Remove<T>(T item)
{
    //SERIOUS code smell here
    var groupName = (string)(object)item
    //stuff
}

//someOtherRepository
public void Remove<T>(T item)
{
    //SERIOUS code smell here
    var request = (RemoveSomethingRequest)(object)item
    //stuff
}

这有很多不好的缺陷,可读性,滥用泛型,通常只是不好等等......

因此,由于该操作的所有方法都返回 void:

委托可以做到这一点吗? 有没有其他方法可以解决这个问题?

【问题讨论】:

  • 我怀疑代码异味可以通过从根本上重新考虑设计来消除。存储库是如何实现和使用的?
  • @phoog 每种类型(例如用户、组、报告等)都有一个特定于其类的存储库。我们如何处理 Crud 操作无法统一,因为我们有时需要通过 Kev、Name 或实际 User 对象添加/编辑/删除用户
  • 检查我编辑的答案是否有其他想法。

标签: c# generics delegates


【解决方案1】:

在我看来,您有不同类型的键:用户有一个 int 键,而组有一个字符串键。所以我会创建一个通用接口,其方法没有类型参数,如下所示:

interface IRepository<TItem, TKey>
{
    void RemoveItem(TItem item);
    void RemoveByKey(TKey key);
    void RemoveByName(string name);
}

实现应该是清楚的,但如果不是发表评论。

编辑:你也可以这样做,但前提是 TKey 和 TItem 永远不会相同,并且永远不会string

interface IRepository<TItem, TKey>
{
    void Remove(TItem item);
    void Remove(TKey key);
    void Remove(string name);
}

【讨论】:

  • 这是真的,除非我有很多存储库,其中包含很多删除方法,这些方法接受不同的东西来删除。可以是 int、string、myObject、yourObject、IEnumerable
  • 在这种情况下,我认为,您的选择是重新设计应用程序(大量工作)、忍受许多重载(混乱)或滥用泛型(也混乱,并且可能需要大量工作) )。
  • 所以我确信这是一个新的通用问题,但为什么它永远不会是一个字符串?
  • @Robert 因为这样删除重载就不是唯一的了。
【解决方案2】:

您可以将泛型参数T 移动到接口本身:

public interface IHandleCrudOperations<TKey, T>
{
    void Remove(TKey item);
    void Add(T item);
    void Edit(T item);
    void Clone(T item);
}

public class UserRepository : IHandleCrudOperations<int, User>
{
    public void Remove(int userKey)
    {
        _context.Users.FirstOrDefault(x => x.UserKey == userKey);
        //stuff
    }

   public void Add(User user)
   {
   }
}

【讨论】:

  • Add、Edit 和 Clone 方法不能是同一类中的整数
  • @Robert - 如果这就是您的意思,您可以为密钥添加一个类型。或者,您可以向对象类型添加一个接口以指定键。
  • 我看到的唯一问题是我无法将它注入到上面的 ExceptionConverter 类中。我必须为每个存储库创建一个异常转换器类
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多