- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个以前从未遇到过的怪异的设计情况...如果使用的是Objective-C,我可以使用类别来解决它,但是我必须使用C#2.0。
首先,一些背景。我在这个类库中有两个抽象层。底层为扫描内容的组件实现了插件架构(抱歉,不能比这更具体)。每个插件都将以某种独特的方式进行扫描,但是插件也会因接受的内容类型而异。由于各种与本次讨论无关的原因,我不想通过插件界面公开泛型。因此,我最终得到了每种内容类型的IScanner接口(interface)和派生接口(interface)。
顶层是一个便利包装,它接受包含各个部分的复合内容格式。不同的扫描仪将需要复合 Material 的不同部分,具体取决于它们感兴趣的内容类型。因此,我需要具有特定于每个IScanner派生接口(interface)的逻辑来解析复合 Material 内容,以查找所需的相关部分。
解决此问题的一种方法是简单地向IScanner添加另一种方法,并在每个插件中实现它。但是,两层设计的重点是插件本身不需要了解复合格式。解决此问题的蛮力方法是在上层进行类型测试和下转换,但是随着将来增加对新内容类型的支持,这些内容将需要仔细维护。在这种情况下,访问者模式也会很尴尬,因为实际上只有一个访问者,但是不同的可访问类型的数量只会随着时间而增加(即,这是适合访问者的相反条件)。另外,当我真正想要的是劫持IScanner的单派调度时,双派调度感觉就像是过分杀了!
如果使用的是Objective-C,则只需在每个IScanner派生的接口(interface)上定义一个类别,然后在其中添加parseContent方法。类别将在上层定义,因此无需更改插件,同时避免了类型测试的需要。不幸的是,C#扩展方法因为基本上是静态的而无法工作(即-与调用站点上使用的引用的编译时类型相关联,而不是像Obj-C Categories那样挂接到动态分配中)。更不用说,我必须使用C#2.0,所以扩展方法甚至对我都不可用。 :-P
那么,有没有一种干净,简单的方法可以解决C#中的问题,类似于用Objective-C类别解决问题的方法呢?
编辑:一些伪代码可以帮助使当前设计的结构变得清晰:
interface IScanner
{ // Nothing to see here...
}
interface IContentTypeAScanner : IScanner
{
void ScanTypeA(TypeA content);
}
interface IContentTypeBScanner : IScanner
{
void ScanTypeB(TypeB content);
}
class CompositeScanner
{
private readonly IScanner realScanner;
// C-tor omitted for brevity... It takes an IScanner that was created
// from an assembly-qualified type name using dynamic type loading.
// NOTE: Composite is defined outside my code and completely outside my control.
public void ScanComposite(Composite c)
{
// Solution I would like (imaginary syntax borrowed from Obj-C):
// [realScanner parseAndScanContentFrom: c];
// where parseAndScanContentFrom: is defined in a category for each
// interface derived from IScanner.
// Solution I am stuck with for now:
if (realScanner is IContentTypeAScanner)
{
(realScanner as IContentTypeAScanner).ScanTypeA(this.parseTypeA(c));
}
else if (realScanner is IContentTypeBScanner)
{
(realScanner as IContentTypeBScanner).ScanTypeB(this.parseTypeB(c));
}
else
{
throw new SomeKindOfException();
}
}
// Private parsing methods omitted for brevity...
}
最佳答案
听起来您在说的是您的内容布局如下:
+--------+| part 1 || type A |+--------+| part 2 || type C |+--------+| part 3 || type F |+--------+| part 4 || type D |+--------+
and you have readers for each part type. That is, an AScanner knows how to process the data in a part of type A (such as part 1 above), a BScanner knows how to process the data in a part of type B, and so forth. Am I right so far?
Now, if I understand you, the problem that you're having is that the type readers (the IScanner
implementations) don't know how to locate the part(s) they recognize within your composite container.
Can your composite container correctly enumerate the separate parts (i.e., does it know where one part ends and another begins), and if so, does each part have some sort of identification that either the scanner or the container can differentiate?
What I mean is, is the data laid out something like this?
+-------------+| part 1 || length: 100 || type: "A" || data: ... |+-------------+| part 2 || length: 460 || type: "C" || data: ... |+-------------+| part 3 || length: 26 || type: "F" || data: ... |+-------------+| part 4 || length: 790 || type: "D" || data: ... |+-------------+
If your data layout is similar to this, could the scanners not request of the container all parts with an identifier matching a given pattern? Something like:
class Container : IContainer{
IEnumerable IContainer.GetParts(string type){
foreach(IPart part in internalPartsList)
if(part.TypeID == type)
yield return part;
}
}
class AScanner : IScanner{
void IScanner.ProcessContainer(IContainer c){
foreach(IPart part in c.GetParts("A"))
ProcessPart(part);
}
}
delegate void PartCallback(IPart part);
class Container : IContainer{
void IContainer.GetParts(PartCallback callback){
foreach(IPart part in internalPartsList)
callback(part);
}
}
class AScanner : IScanner{
void IScanner.ProcessContainer(IContainer c){
c.GetParts(delegate(IPart part){
if(IsTypeA(part))
ProcessPart(part);
});
}
bool IsTypeA(IPart part){
// determine if part is of type A
}
}
- The scanners should not have any knowledge of the container type.
- The container type has no built-in intelligence. It is as close to plain old data as you can get in C#.
- I can't change the container type; It is part of an existing architecture.
IScanner
接口(interface)不应该知道IContainer
接口(interface),以便将来有自由更改IContainer
接口(interface)的权限,则可以采用以下两种方法之一进行折衷:IPartProvider
接口(interface),该接口(interface)是IContainer
派生自(或包含)的。该IPartProvider
仅提供提供零件服务的功能,因此它应该非常稳定,并且可以在与IScanner
相同的程序集中定义,因此您的插件无需引用定义了IContainer
的程序集。 IScanner
除外)。 IScanner
派生形式,即定义了唯一扫描”方法,并且
CompositeScanner
类对每种零件类型都有唯一的“解析”方法。
IScanner
接口(interface)的实现者)与主应用程序分离,而我假设这是
CompositeScanner
类所在的地方。我较早的建议之一是如何实现该目标,但具体细节取决于
parseType
X函数的工作方式。这些可以抽象和概括吗?
parseType
X函数与
Composite
类对象进行通信以获得所需的数据。是否可以将它们移到通过
Parse
类代理的
IScanner
接口(interface)上的
CompositeScanner
方法中,以便从
Composite
对象获取此数据?像这样的东西:
delegate byte[] GetDataHandler(int offset, int length);
interface IScanner{
void Scan(byte[] data);
byte[] Parse(GetDataHandler getData);
}
class Composite{
public byte[] GetData(int offset, int length){/*...*/}
}
class CompositeScanner{}
IScanner realScanner;
public void ScanComposite(Composite c){
realScanner.Scan(realScanner.Parse(delegate(int offset, int length){
return c.GetData(offset, length);
});
}
}
Parse
上的单独
IScanner
方法并将简单的
GetDataHandler
委托(delegate)直接传递给
Scan
来简化此操作(如果需要,其实现可以调用私有(private)
Parse
)。然后,代码看起来与我之前的示例非常相似。
// parts identified by their offset within the file
class MainApp{
struct BlockBounds{
public int offset;
public int length;
public BlockBounds(int offset, int length){
this.offset = offset;
this.length = length;
}
}
Dictionary<Type, BlockBounds> plugins = new Dictionary<Type, BlockBounds>();
public void RegisterPlugin(Type type, int offset, int length){
plugins[type] = new BlockBounds(offset, length);
}
public void ScanContent(Container c){
foreach(KeyValuePair<Type, int> pair in plugins)
((IScanner)Activator.CreateInstance(pair.Key)).Scan(
c.GetData(pair.Value.offset, pair.Value.length);
}
}
// parts identified by name, block length stored within content (as in diagram above)
class MainApp{
Dictionary<string, Type> plugins = new Dictionary<string, Type>();
public void RegisterPlugin(Type type, string partID){
plugins[partID] = type;
}
public void ScanContent(Container c){
foreach(IPart part in c.GetParts()){
Type type;
if(plugins.TryGetValue(part.ID, out type))
((IScanner)Activator.CreateInstance(type)).Scan(part.Data);
}
}
}
Activator.CreateInstance
方法,那么最好不要使用
RegisterPlugin
。
关于c# - 有没有一种简单的方法可以在C#中模拟Objective-C类别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/421119/
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
在现代 IDE 中,有一个键盘快捷键可以通过键入文件名称来打开文件,而无需将手放在鼠标上。例如: Eclipse:Cmd|Ctrl + Shift + R -> 打开资源 IntelliJ:Cmd|C
有什么东西会等待事件发生(我正在等待的是 WebBrowser.DocumentCompleted),然后执行代码吗?像这样: If (WebBrowser.DocumentCompleted) 不会
我使用 PHP Minify,它很棒。但我的问题是,是否有任何 PHP 插件或其他东西可以自动检测 javascript/css 代码并自动缩小它?谢谢。 最佳答案 Javascript 压缩器? 看
有没有一种语言,类似什么CoffeeScript是JavaScript,编译成windows batch|cmd|command line的语言? 我指的cmd版本是基于NT的,尤其是XP sp3及以
我知道我可以 ,但是,我真的宁愿有一个任务,我可以从任何可以使用所有(或至少大部分)属性的操作系统调用 copy ,但这并没有消除 unix 上的权限。 我想知道是否已经有解决方案,或者我必须自己编
我正在使用 Vuejs(不使用 jQuery)开发一个项目,该项目需要像 jvectormap 这样的 map 但正如我所说,我没有使用 jQuery,那么是否有任何其他库可以在不使用 jQuery
想要进行一个简单的民意调查,甚至不需要基于 cookie,我不在乎投了多少票。有没有类似的插件或者简单的东西? 最佳答案 这是一个有用的教程 - 让我知道它是否适合您 using jQuery to
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
var FileBuff: TBytes; Pattern: TBytes; begin FileBuff := filetobytes(filename); Result := Co
我想要一个 vqmod xml 文件来添加一次上传多个图像的功能。身边有这样的事吗? 编辑:Opencart版本:2.1.0.1 最佳答案 最后我写了一个xml来添加到opencart 2.1.0.1
所以考虑这样的函数: public void setTemperature(double newTemperatureValue, TemperatureUnit unit) 其中Temperatur
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我是 ggplot2 的新手,一直在尝试找到一个全面的美学列表。我想我理解它们的目的,但很难知道哪些可以在各种情况下使用(主要是几何图形?)。 Hadley 的网站偶尔会在各个几何图形的页面上列出可用
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
是否有任何 PHP 函数可以将整数转换为十万和千万? 900800 -> 9,00,800 500800 -> 5,00,800 最佳答案 由于您已在问题标签中添加了 Yii,因此您可以按照 Yii
使用 Clojure 一段时间后,我积累了一些关于它的惰性的知识。我知道诸如map之类的常用API是否是惰性的。然而,当我开始使用一个不熟悉的API(例如with-open)时,我仍然感到怀疑。 是否
我的项目需要一个像 AvalonDock 这样的对接系统,但它的最后一次更新似乎是在 2013 年 6 月。是否有更多...积极开发的东西可以代替它? 最佳答案 AvalonDock 实际上相当成熟并
我正在寻找一个可以逆转 clojure 打嗝的函数 所以 turns into [:html] 等等 根据@kotarak的回答,这现在对我有用: (use 'net.cgrand.enliv
我是一名优秀的程序员,十分优秀!