我们需要在具有静态方法的代码中使用非托管库。我想在我的代码中将库操作作为依赖项引入。除了具有静态方法之外,库还具有初始化方法和设置方法,两者都是全局的。所以我不能将它包装在一个实例类中,因为如果一个实例更改了一个设置,那么所有其他实例都会受到影响,如果一个实例被初始化,所有其他实例都将被重新初始化。
我想过将它作为单身人士课程介绍。这样它将在实例类中,但只有一个实例,因此我不必担心更改设置或初始化。您如何看待这种方法?我对依赖注入模式很新,我不确定单例模式是否是一个好的解决方案?您的解决方案对于类似案例会有什么影响?
编辑:初始化也需要一个参数,所以我不能只是锁定方法调用,并在每次调用时重新初始化和更改设置。
编辑2:以下是一些方法的签名:
public static void Initialize(int someParameter)
// Parameter can only be changed by re-initalization which
// will reset all the settings back to their default values.
public static float[] Method1(int someNumber, float[] someArray)
public static void ChangeSetting(string settingName, int settingValue)
答案 0 :(得分:10)
如果你只需要在启动时设置一次,那么我建议创建一个非静态包装类,它在自己的静态构造函数中完成静态类的所有初始化。这样你可以放心,它只会发生一次:
public class MyWrapper
{
public MyWrapper()
{
// Do any necessary instance initialization here
}
static MyWrapper()
{
UnManagedStaticClass.Initialize();
UnManagedStaticClass.Settings = ...;
}
public void Method1()
{
UnManagedStaticClass.Method1();
}
}
但是,如果您每次调用它时都需要更改设置,并且希望使实例具有线程安全性,那么我建议您锁定静态对象,以免意外覆盖静态他们仍在使用另一个帖子的设置:
public class MyWrapper
{
public MyWrapper()
{
// Do any necessary instance initialization here
}
static MyWrapper()
{
UnManagedStaticClass.Initialize();
}
static object lockRoot = new Object();
public void Method1()
{
lock (lockRoot)
{
UnManagedStaticClass.Settings = ...;
UnManagedStaticClass.Method1();
}
}
}
如果您需要将初始化参数传递到类的实例构造函数中,那么您也可以通过使用静态标志字段来执行此操作:
public class MyWrapper
{
public MyWrapper(InitParameters p)
{
lock (lockRoot)
{
if (!initialized)
{
UnManagedStaticClass.Initialize(p);
initialized = true;
}
}
}
static bool initialized = false;
static object lockRoot = new Object();
public void Method1()
{
lock (lockRoot)
{
UnManagedStaticClass.Settings = ...;
UnManagedStaticClass.Method1();
}
}
}
如果你还需要每次重新初始化,但是你担心性能因为重新初始化太慢,那么唯一的另一个选择(在可怕的单例之外)是自动检测你是否需要重新初始化 - 初始化,只在必要时才这样做。至少那时,唯一的时间是两个线程同时使用两个不同的实例。你可以这样做:
public class MyWrapper
{
public MyWrapper(InitParameters initParameters, Settings settings)
{
this.initParameters = initParameters;
this.settings = settings;
}
private InitParameters initParameters;
private Settings settings;
static MyWrapper currentOwnerInstance;
static object lockRoot = new Object();
private void InitializeIfNecessary()
{
if (currentOwnerInstance != this)
{
currentOwnerInstance = this;
UnManagedStaticClass.Initialize(initParameters);
UnManagedStaticClass.Settings = settings;
}
}
public void Method1()
{
lock (lockRoot)
{
InitializeIfNecessary();
UnManagedStaticClass.Method1();
}
}
}
答案 1 :(得分:1)
我会使用无状态服务类,并在每次调用方法时传入静态类的状态信息。在不知道你的任何细节的情况下,我将用c#静态类来展示另一个例子。
public static class LegacyCode
{
public static void Initialize(int p1, string p2)
{
//some static state
}
public static void ChangeSettings(bool p3, double p4)
{
//some static state
}
public static void DoSomething(string someOtherParam)
{
//execute based on some static state
}
}
public class LegacyCodeFacadeService
{
public void PerformLegacyCodeActivity(LegacyCodeState state, LegacyCodeParams legacyParams)
{
lock (_lockObject)
{
LegacyCode.Initialize(state.P1, state.P2);
LegacyCode.ChangeSettings(state.P3, state.P4);
LegacyCode.DoSomething(legacyParams.SomeOtherParam);
//do something to reset state, perhaps
}
}
}
你必须填补空白,但希望你能得到这个想法。关键是要将静态对象上的状态设置为所需的最短时间,并锁定整个时间段的访问权限,这样其他调用者就不会受到全局状态更改的影响。您必须创建此类的新实例才能使用它,因此它是完全可注入和可测试的(除了提取界面的步骤,我为简洁起见跳过了这一步。)
这里的实施有很多选择。例如,如果您必须经常更改LegacyCodeState,但只能更改少数特定状态,则可能会有重载来管理这些状态。
修改强>
这在很多方面比单身人更可取,最重要的是你将无法累积并耦合到全局状态:如果它是唯一的入口点,则会将全局状态转换为非全局状态你的静态类。但是,如果你最终需要一个单例,你可以通过在这里封装构造函数来轻松切换。
public class LegacyCodeFacadeService
{
private LegacyCodeFacadeService() { }
public static LegacyCodeFacadeService GetInstance()
{
//now we can change lifestyle management strategies later, if needed
return new LegacyCodeFacadeService();
}
public void PerformLegacyCodeActivity(LegacyCodeState state, LegacyCodeParams legacyParams)
{
lock (_lockObject)
{
LegacyCode.Initialize(state.P1, state.P2);
LegacyCode.ChangeSettings(state.P3, state.P4);
LegacyCode.DoSomething(legacyParams.SomeOtherParam);
//do something to reset state, perhaps
}
}
}