Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在外部类的每个方法调用周围自动添加锁?_C# - Fatal编程技术网

C# 如何在外部类的每个方法调用周围自动添加锁?

C# 如何在外部类的每个方法调用周围自动添加锁?,c#,C#,我有一个来自外部开发人员的dll,它是基于C的,并且周围有一个C#包装器。单个调用不是线程安全的,根据开发人员的说法,我需要自己锁定每个调用 我开始在其中一些代码中添加锁,并注意到这是一个很难实现的问题(让人麻木的代码片段复制粘贴),并导致我的代码变得非常难看和不可读。我现在想知道是否有更简单的方法。现在看起来是这样的: lock (LockObject) Wrapper.DeleteAllSequences(); lock (LockObject) Wrapper.Upload

我有一个来自外部开发人员的dll,它是基于C的,并且周围有一个C#包装器。单个调用不是线程安全的,根据开发人员的说法,我需要自己锁定每个调用

我开始在其中一些代码中添加锁,并注意到这是一个很难实现的问题(让人麻木的代码片段复制粘贴),并导致我的代码变得非常难看和不可读。我现在想知道是否有更简单的方法。现在看起来是这样的:

lock (LockObject)
    Wrapper.DeleteAllSequences();
lock (LockObject)
    Wrapper.UploadSequence();
lock (LockObject)
    Wrapper.StartSequence();

必须有某种构造自动在我从包装器调用的每个方法周围添加一个锁,而不是每次都要求我手动执行此操作。

正如@JHBonarius所建议的,您可以像这样重构,使用一个方法对应一个目标方法签名:

public void CallLocked(Action method)
{
  if (method != null)
    lock (LockObject)
      method();
}
用法:

CallLocked(Wrapper.DeleteAllSequences);
或:

您需要创建与需要调用的不同方法签名一样多的
CallLocked
重载

例如,由于没有语言关键字,因此即使这似乎是一个糟糕的解决方案,您也只能这样做:

threadlock Wrapper.DeleteAllSequences();
我写它似乎是因为在
CallLocked
中,您可以添加任何
try catch
和其他您想要的流控制管理

enum ExceptionBehavior { Hide, Show, Raise };

public void CallLocked(Action method, 
                       ExceptionBehavior exceptionBehavior = ExceptionBehavior.Raise)
{
  if (method != null)
    lock (LockObject)
      try
      {
        method();
      }
      catch ( Exception ex )
      {
        switch ( exceptionBehavior )
        {
          case ExceptionBehavior.Hide;
            break;
          case ExceptionBehavior.Show;
            MessageBox.Show(...);
            break;
          case ExceptionBehavior.Raise;
            throw;
        }
      }
}

当然,您可以添加一些行为,如
HideAndLog
ShowAndLog
RaiseAndLog
。。。并使用一个全局变量来设置默认行为。

我会说:要么更改包装器,要么围绕包装器构建一个包装器……没有理由这么做。您需要在试图从多个线程访问该方法的代码周围设置一个锁。您需要确定哪些方法也可以在单个线程中运行-如果多个线程依次调用
DeleteAllSequences()
uploadSequence()
该怎么办?使用多个锁将允许这样做。我怀疑这是你想要的。首先,你有多个线程吗?您正在构建什么样的应用程序?图书馆做什么?如果需要在单个线程中运行这3个方法,可以使用
lock(xx){Wrapper.DeleteAllSequences();Wrapper.UploadSequence();Wrapper.UploadSequence();}
。另一方面,通过将相关代码放在使用自己线程的单独类中,可以确保只有一个线程可以访问该库。或者,如果您可以在一个调用中组合所有库操作,您可以使用一个ActionBlock,它在每个输入消息中只使用一个线程default@JHBonarius是的,我就是这么想的,但我不想这么做:D希望有一个我不知道的结构可以让我跳过它work@DanielM你所要求的并不存在,正如我所知,因此您必须像使用
calllock
一样实现它。这与使用
lock
没有什么不同,并且不会防止多个线程从中调用方法sequence@PanagiotisKanavos也许你不理解OP的问题。看看你的代码和OP的代码。区别在于两个字符。如果使用
lock(x)
此代码实际上比原始代码更糟糕。如果你真的不想我投反对票,你可以写
lock(x){Wrapper.DeleteAllSequences();}
,但是JHBonarious建议放弃原来的包装,创建一个不需要手动锁定的更好的包装。只要将
放入
DeleteAllSequences()
等中,就不需要手动锁了。@OlivierRogier在您的情况下,每次实际调用包装器时,我仍然需要编写CallLocked()。我的理想解决方案是“神奇地”将锁添加到包装器的每个调用中,而不必担心它。(但也不是我的反对票)
enum ExceptionBehavior { Hide, Show, Raise };

public void CallLocked(Action method, 
                       ExceptionBehavior exceptionBehavior = ExceptionBehavior.Raise)
{
  if (method != null)
    lock (LockObject)
      try
      {
        method();
      }
      catch ( Exception ex )
      {
        switch ( exceptionBehavior )
        {
          case ExceptionBehavior.Hide;
            break;
          case ExceptionBehavior.Show;
            MessageBox.Show(...);
            break;
          case ExceptionBehavior.Raise;
            throw;
        }
      }
}