Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.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#_.net_Design Patterns - Fatal编程技术网

C# 订单敏感调用的设计模式

C# 订单敏感调用的设计模式,c#,.net,design-patterns,C#,.net,Design Patterns,我正在设计一个小型目录同步引擎,它可以接受不同类型的源并处理增量同步。我已经为DirectorySource定义了一个接口,该接口当前如下所示: public interface IDirectorySource { IEnumerable<IDirectoryEntry> GetChanges(IList<string> attributes, IChangeToken token); } Tuple<IEnumerable<IDirectoryE

我正在设计一个小型目录同步引擎,它可以接受不同类型的源并处理增量同步。我已经为DirectorySource定义了一个接口,该接口当前如下所示:

public interface IDirectorySource
{
    IEnumerable<IDirectoryEntry> GetChanges(IList<string> attributes, IChangeToken token);
}
Tuple<IEnumerable<IDirectoryEntry>, IChangeToken> GetChanges(IList<string> attributes, IChangeToken token);
public interface IChangeSet : IEnumerable<IDirectoryEntry>
{
    IChangeToken GetToken();
}
IChangeSet result = source.GetChanges(attributes, token);

foreach (IDirectoryEntry entry in result) {
    // Do something with the data...
}

IChangeToken resultToken = result.GetToken();
公共接口IDirectorySource
{
IEnumerable GetChanges(IList属性、IChangeToken标记);
}
为了避免不必要的内存分配,我确实希望提供一个枚举器而不是列表,但我的问题是,我还希望返回一个新的IChangeToken,其中包含下次调用GetChanges(进行增量更新)所需的新状态信息。由于其他人可能在不同调用之间更新目录,因此必须在枚举完成后计算changetoken

我曾考虑过使用第二个IChangeToken参数来接收新的令牌,但这感觉不太好(而且不一致,因为令牌将立即返回,但在枚举完成之前无法填充)。。我曾考虑过返回类似“IChangeSet”的接口,该接口包含一个GetEnumerator方法和一个GetToken方法,但问题仍然是对enumerator方法的后续调用返回不同的数据(因此具有不同的ChangeToken)

我如何设计一个接口,使我的接口的用户“不可能”在我的GetChanges枚举器和检索关联的ChangeToken时错误地使用它


我希望我的问题有意义。。我很难弄清楚我的问题应该用什么标题……;)

在函数式编程语言中有一种称为Tuple的结构。在这里,我相信Tuple是最好的选择——每个设计的Tuple意味着它的项之间没有关系。当前版本的.NET Framework(3.5)不支持元组,但下一个版本(4.0)支持元组。如果需要,您可以自己实现Tuple,这没什么大不了的。不幸的是,C#缺少对元组的语言支持,但例如F#就没有

总之,让您的界面如下所示:

public interface IDirectorySource
{
    IEnumerable<IDirectoryEntry> GetChanges(IList<string> attributes, IChangeToken token);
}
Tuple<IEnumerable<IDirectoryEntry>, IChangeToken> GetChanges(IList<string> attributes, IChangeToken token);
public interface IChangeSet : IEnumerable<IDirectoryEntry>
{
    IChangeToken GetToken();
}
IChangeSet result = source.GetChanges(attributes, token);

foreach (IDirectoryEntry entry in result) {
    // Do something with the data...
}

IChangeToken resultToken = result.GetToken();
Tuple GetChanges(IList属性、IChangeToken标记);

我尝试了一种方法,使用了我在原始问题中考虑的“IChangeSet”。在该场景中,IDirectorySource接口如下所示:

public interface IDirectorySource
{
    IChangeSet GetChanges(IList<string> attributes, IChangeToken token);
}
即使可以在枚举之前调用“GetToken()”-方法(这可能是错误的),如果在枚举完成之前调用函数,我也可以返回旧标记


感觉不是100%,但这是我目前能想到的最好的

@Per:在哪种情况下,您希望获得相同的令牌,而在哪种情况下,您希望获得不同的令牌?在不同的GetChanges调用之间,令牌(几乎)从不相同。自上次同步调用GetChanges以来,当您获得当前更改时,始终会计算该值。在我当前的两个DirectorySource实现测试中,令牌可以是来自“DirSync”调用的字节数组cookie,也可以是来自域控制器的usnChanged值(本质上它是一个时间戳)。我不知道这个答案是否有道理是的,即使对结果进行“foreach”调用可能会有点不利,但这确实会起作用。但我还有一个问题(我将更新我的问题),那就是changetoken在枚举完成之前不可用。您可以实现元组中两个项之间的关系-如果客户端在枚举之前尝试调用IChangeToken的任何方法-抛出异常。由于存在一种关系,即使是隐藏的,元组结构也不再合适。在你的合同中,你希望客户遵循严格而复杂的行为。应该严格按照顺序调用接口的方法,它看起来像一个状态。也许,您应该返回一个复杂的对象,该对象将维护状态并对客户机隐藏所有子节点行为。。我现在意识到,这与我原来的想法没有多大改变。它只是稍微多连接一点枚举器和令牌,但仍然允许对枚举器进行多次调用,然后GetToken调用可能会“不同步”。。