C# 确保在区域内访问对象(列表),但可在外部引用的策略
我正在考虑创建一个ServiceManager区域(一组带有门面接口的类),其他区域可以通过该区域注册并提供“服务”,并传递请求。我计划在它自己的线程中运行这个类,并且我希望将关键区域保持在最小值,并且完全在这个区域内处理 当一个区域注册时,他们会得到自己的收件箱和发件箱命令,这是一个ServiceRequests列表 现在,我的困境是,如果我不共享发件箱(服务提供商区域)的链接,我将需要通过搜索匹配项来定位发件箱(所有注册的关键区域,并且由于这一点,所有提交的请求也会破坏本地发件箱的目的) 备选方案我在ServiceManager区域之外提供一个链接,然后对一个新的外部区域进行编码,这样就可以跳过关键区域,直接更新列表,绕过此区域C# 确保在区域内访问对象(列表),但可在外部引用的策略,c#,multithreading,C#,Multithreading,我正在考虑创建一个ServiceManager区域(一组带有门面接口的类),其他区域可以通过该区域注册并提供“服务”,并传递请求。我计划在它自己的线程中运行这个类,并且我希望将关键区域保持在最小值,并且完全在这个区域内处理 当一个区域注册时,他们会得到自己的收件箱和发件箱命令,这是一个ServiceRequests列表 现在,我的困境是,如果我不共享发件箱(服务提供商区域)的链接,我将需要通过搜索匹配项来定位发件箱(所有注册的关键区域,并且由于这一点,所有提交的请求也会破坏本地发件箱的目的) 备
我的解决方案是在ServiceManager区域的代码中创建一个“key”对象,其中直接访问永远不会离开该区域(包括完全空的任何对象都可以工作) 当一个区域注册后,他们将得到一个类作为回报,其中包含指向上述对象的链接以及指向注册区域的ServiceManager对象所在位置的链接。(其中包含直接的收件箱/发件箱链接以及其他信息) 此“令牌”对象还包含以下代码
public ServiceObject GetServiceObject(Key key)
{
If (key == this.key)
{
return serviceObject;
}
return null
{
这样,即使命令是公共的,其内容也只能在ServiceManager区域内访问,因为它是唯一可以直接访问密钥对象的区域。这绕过了上述两个问题:在所有服务用户之间共享关键区域,以及这些服务用户直接访问其列表的风险
因此,它解决了问题,但对我来说,这看起来真的很难看,有没有更聪明的方法,以及如何使用System.Collections.Concurrent中的类?它们有高效的锁定实现,还提供生产者/消费者行为以及分配工作负载的分区 使用这些类,您将能够对任何场景进行建模,无论您是拥有多个读者、多个作者,还是同时拥有这两者。无需编写任何自己的锁定代码 更新:包装队列以提供外观的示例代码,用于将来将命令队列可选地拆分为多个队列 让我们假设您对向队列中插入命令的线程数量的关注有一定的价值。您可以通过在底层队列周围创建一个瘦包装器来覆盖自己,这允许您在以后发现有必要时传递不同的包装器实例
public interface ICommandQueue {
void Add( Command command );
}
public class CommandQueue : ICommandQueue {
private ConcurrentQueue<Command> queue = new ConcurrentQueue<Command>();
public void Add( Command command ) {
queue.Enqueue( command );
}
}
这将允许您在以后更改队列的数量,而不是现在编写所有(可能不必要的)代码。永远不要解决一个你不确定的问题:-)
更多信息:
public interface ICommandQueue {
void Add( Command command );
}
public class CommandQueue : ICommandQueue {
private ConcurrentQueue<Command> queue = new ConcurrentQueue<Command>();
public void Add( Command command ) {
queue.Enqueue( command );
}
}
这将允许您在以后更改队列的数量,而不是现在编写所有(可能不必要的)代码。永远不要解决一个你不确定的问题:-)
更多信息:
//base class of no use on its own. Used to lock the AreaIdentifier
public class Key
{
public Key()
{
}
}
//public direct link to ServiceArea info, without ability to access it without the internal key
public class AreaIdentifier
{
Key key;
ServiceArea serviceArea;
public AreaIdentifier(ServiceArea serviceArea, Key key)
{
this.key = key;
this.serviceArea = serviceArea;
}
public ServiceArea GetServiceArea(Key key)
{
if (this.key == key) return serviceArea;
return null;
}
}
}
采用这种方法的原因是,外部区域的编码方式必须确保“传输层”的“内部代码”以及添加和删除操作不会弄乱操作。现在如果我共享一个直接链接
因此,当外部区域(在它自己的线程中)想要添加一个新命令时,它通过调用位于通信层代码中的以下调用来完成。(此区域内有一个私钥变量,无法通过AreaIdentifier访问(但已知),也无法在区域外以其他方式共享
//Put a command in the outBox for pickup by CommunicationLayer
public Boolean AddCommand(AreaIdentifier area, CommandRequest command)
{
//attempt enter critical region or return false;
ServiceArea temparea = area.GetServiceArea(key);
List<Command> tempOutbox = temparea.GetOutBox();
tempOutbox.Add(command);
//exit critical region
return true;
}
//将命令放入发件箱,以便通信层拾取
公共布尔AddCommand(AreaIdentifier区域,CommandRequest命令)
{
//试图进入关键区域或返回false;
ServiceArea temparea=area.GetServiceArea(键);
List tempOutbox=temparea.GetOutBox();
添加(命令);
//出口临界区
返回true;
}
我从这种方法中看到的唯一缺点是,我有“GetServiceArea”的公共功能,这在TransportLayer的“内部”功能之外没有什么意义。我目前使用的代码是这样的
//base class of no use on its own. Used to lock the AreaIdentifier
public class Key
{
public Key()
{
}
}
//public direct link to ServiceArea info, without ability to access it without the internal key
public class AreaIdentifier
{
Key key;
ServiceArea serviceArea;
public AreaIdentifier(ServiceArea serviceArea, Key key)
{
this.key = key;
this.serviceArea = serviceArea;
}
public ServiceArea GetServiceArea(Key key)
{
if (this.key == key) return serviceArea;
return null;
}
}
}
采用这种方法的原因是,外部区域的编码方式必须确保“传输层”的“内部代码”以及添加和删除操作不会弄乱操作
因此,当外部区域(在它自己的线程中)想要添加一个新命令时,它会通过调用位于通信层代码中的以下调用来完成。(该区域内有一个私钥变量,不能通过AreaIdentifier访问(但已知),也不能在区域外以其他方式共享。)
//Put a command in the outBox for pickup by CommunicationLayer
public Boolean AddCommand(AreaIdentifier area, CommandRequest command)
{
//attempt enter critical region or return false;
ServiceArea temparea = area.GetServiceArea(key);
List<Command> tempOutbox = temparea.GetOutBox();
tempOutbox.Add(command);
//exit critical region
return true;
}
//将命令放入发件箱,以便通信层拾取
公共布尔添加命令(A)