使用ImpromptuInterface反射库方便的创建自定义DfaGraphWriter (2)

然后,我们可以使用ImpromptuInterface ActLike<>方法创建实现了IDfaMatcherBuilder的代理对象。此代理包装rawbuilder对象,因此当您在接口上调用方法时,它将在底层调用DfaMatcherBuilder中的等效的方法:

使用ImpromptuInterface添加包装代理

在代码中,如下所示:

// An instance of DfaMatcherBuilder in an object reference object rawBuilder = _services.GetRequiredService(matcherBuilder); // wrap the instance in the ImpromptuInterface interface IDfaMatcherBuilder builder = rawBuilder.ActLike<IDfaMatcherBuilder>(); // we can now call methods on the builder directly, e.g. object rawTree = builder.BuildDfaTree();

原始DfaMatcherBuilder.BuildDfaTree()方法和接口版本之间有一个重要区别:原始方法返回一个DfaNode,但这是另一个internal类,因此我们无法在接口中引用它。

相反,我们为DfaNode类创建另一个ImpromptuInterface,暴露我们将需要的属性(在接下来的文章中你就会明白为什么我们需要他们):

public interface IDfaNode { public string Label { get; set; } public List<Endpoint> Matches { get; } public IDictionary Literals { get; } // actually a Dictionary<string, DfaNode> public object Parameters { get; } // actually a DfaNode public object CatchAll { get; } // actually a DfaNode public IDictionary PolicyEdges { get; } // actually a Dictionary<object, DfaNode> }

在下一篇文章中,我们将在WriteNode的方法中使用这些属性,但是有一些复杂性。在原始DfaNode类中,Parameters和CatchAll属性返回DfaNode对象。在我们IDfaNode版本的属性中,我们必须返回object。我们无法引用DfaNode(因为是internal)并且我们不能返回IDfaNode,因为DfaNode 它没有实现IDfaNode,因此您不能将object引用隐式转换为IDfaNode。你必须使用ImpromptuInterface来显式地添加一个实现了接口的代理,。

例如:

// Wrap the instance in the ImpromptuInterface interface IDfaMatcherBuilder builder = rawBuilder.ActLike<IDfaMatcherBuilder>(); // We can now call methods on the builder directly, e.g. object rawTree = builder.BuildDfaTree(); // Use ImpromptuInterface to add an IDfaNode wrapper IDfaNode tree = rawTree.ActLike<IDfaNode>(); // We can now call methods and properties on the node... object rawParameters = tree.Parameters; // ...but they need to be wrapped using ImpromptuInterface too IDfaNode parameters = rawParameters.ActLike<IDfaNode>();

返回Dictionary类型的属性还有另一个问题:Literals和PolicyEdges。实际返回的类型分别为Dictionary<string, DfaNode>和Dictionary<object, DfaNode>,但是我们需要使用一个不包含该DfaNode类型的类型。不幸的是,这意味着我们不得不退回到.NET 1.1 IDictionary接口!

您不能将一个Dictionary<string, DfaNode>强制转换为IDictionary<string, object>,因为这样做将是不安全的协方差形式。

IDictionary是一个非泛型接口,因此key和value仅作为object公开。对于string键,您可以直接进行转换,对于,DfaNode我们可以使用ImpromptuInterface为我们创建代理包装器:

// Enumerate the key-value pairs as DictinoaryEntrys foreach (DictionaryEntry dictEntry in node.Literals) { // Cast the key value to a string directly var key = (string)dictEntry.Key; // Use ImpromptuInterface to add a wrapper IDfaNode value = dictEntry.Value.ActLike<IDfaNode>(); }

现在,我们已经拥有了通过实现WriteNode来创建自定义DfaWriter实现所需的一切对象,但是这篇文章已经有点长了,所以我们将在下一篇文章中探讨如何实现这一点!

摘要

在本文中,我探讨了DfaWriter在ASP.NET Core 中的实现以及它使用的两个internal类:DfaMatcherBuilder和DfaNode。这些类是内部类的事实使得创建我们自己的DfaWriter实现非常棘手。为了干净地实现它,我们将不得不重新实现这两种类型以及它们所依赖的所有类。

作为替代,我使用ImpromptuInterface库创建了一个包装器代理,该代理实现与被包装的对象拥有类似的方法。这使用反射来调用包装属性上的方法,但允许我们使用强类型接口。在下一篇文章中,我将展示如何使用这些包装器创建一个定制的DfaWriter来进行端点图的自定义。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzzdf.html