返回首页

{A}
{S0}简介
本文介绍了一个实际使用情况和LINQ到XML。
这是第二个和最后一部分的quot;利用LINQ to XML的查询混淆mapquot条循环。推荐阅读{A2} - 这会给你一个更好的理解下面描述的东西。
{A2},我们使用的LINQ to XML查询提供其混淆名称的混淆地图搜索原始类型的名称。现在,我想向您展示我们如何使用先进的LINQ查询,以提供更复杂的搜索任务,如原始类型的成员名称搜索。任务定义
正如先前定义的,用户界面​​应尽可能简单。所以我决定限制两个编辑器的用户界面。首先是用来提供混淆地图文件名,另一个是用户的搜索请求。
让我们看看在三种可能的用户使用的投入作为搜索条件: - 这是,当然,搜索请求为混淆类型quot; aquot;。AB - 这是不太清楚 - 它可能是一个复杂的类型名称quot; a.bquot,或一个字段名为quot; bquot;类型quot; aquot。我们不能区分这些情况,所以我们将搜索 - 类型和字段。AB(System.String,INT) - 这是,当然,与签名的方法,搜索请求(字符串,整型)。
注:完整的方法签名包含一个结果类型,但以来NET不支持基础上的结果类型的重载,我们并不需要它。
会员搜索任务可以分为两个步骤:键入搜索。会员搜索的第一步结果。
我们已经有一个代码来完成的第一步。要使用它,我们只需要提供模糊的类型名称。因此,一个更详细的步骤列表是:检测使用什么类型的输入;解析输入到单独的类型名称和成员名称;解析成员的名称,以获取方法签名;搜索与分析的类型名称的类型;搜索解析成员名称相匹配的类型成员之间的字段或方法。 会员名称搜索
分开成员名称类型的名称,我们可以拆分输入字符串使用quot; quot;分离器和成员名称的最后一部分。但我们可以看到点也存在于一个方法的签名,我决定更换签名点别的东西,让我用一个虚线的类型名称分裂。下面的代码替换quot; quot; quot; / quot;在方法签名,如果有的话。

// Replace dots within method parameters with '/' to correctly split names.

int sigIndex = obfuscatedName.IndexOf('(');

if (sigIndex > 0) // Signature is present.



  // Explicit conversion required for IEnumerable extension methods call.

  obfuscatedName = new string(((IEnumerable<char>)obfuscatedName) 

    .Select((c, i) => i <= sigIndex ?  // If index less then signature start

        c :                  // bypass characters.

        c == '.' ? '/' : c)  // Otherwise if character inside signature 

                             // is '.' replace it with '/' otherwise bypass.

    .ToArray());

此代码检测签名存在搜索​​quot;("符号,并取代所有quot; quot; quot; /"里面使用索引的选择扩展方法的签名。
现在,我们可以分裂混淆的名称,除了通过简单地调用obfuscatedName.Split ('.')方法。最后一个子方法签名或字段的名称。
方法签名需要一些额外的解析,检测的参数类型,和平等常规,将比较的签名。我实现了这个逻辑,在Signature类。为了实现代码的统一,我也代表现场搜索请求使用签名类 - 使任何类型的成员搜索请求将签名的实例。签名有三个主要成员:BOOL IsMethod - 表示如果这是一个方法的签名。BOOL MemberName - 类型成员的名称。BOOL SygEquals(字符串SIG) - 检查,如果传递的签名字符串等于实例。
我不会提供Signature类的实现细节,因为他们是微不足道的,你可以从他们在文章开始的代码示例。
有两种类型,以搜索:第一个是类型齐全,涵盖了整个搜索字符串(例如,类型名称quot; a.bquot;输入quot; a.bquot;)另一种是不完整的类型,部分涵盖除姓氏元素(例如,类型名quot; aquot;输入quot; a.bquot;)输入字符串。这种类型是必需的成员搜索,正如我们前面定义。
注:还有一件事,我想显示的是如何声明一个匿名类型的数组之前,用数据填充它。例如,要声明一个匿名类型的数组,并填写数据取决于一些条件,然后处理这个数组。在这种情况下,我用的是一个模式:{C}
这种方法允许你不定义命名类型,当你不需要它们。我使用这种模式来定义一个类型的数组,如果此类型是一个完整的的一个标志,指示搜索。
// Define array of anonymous types  - tricky but its works.

var typeNames = new[] { new { Name = "", IsComplete = false } };

现在我们需要重写原始类型的搜索查询使用类型名称阵列。
// Define type query.

var types = from type in map.Descendants("type")

           join tname in typeNames on 

             (type.Element("newname") ?? type.Element("name")).Value 

             equals tname.Name

           select new { TypeElement = type, IsComplete = tname.IsComplete };

这里使用JOIN操作允许我提供一个容易过滤后的类型名称数组。匿名类型的投影将查询结果。这一预测包含发现的类型元素的指示标志和类型的完整性。为了让所有的类型,我们可以使用一个简单的表达式:
types.Where(t => t.IsComplete);

注意:LINQ查询使用延迟执行的基础;,这意味着查询的执行被延迟,直到此刻您访问的数据,和更 - 查询将执行每次访问。下面的代码演示了此行为:
XElement xml = new XElement("parent",

               new XElement("child1")

             );



// Query that retrieve all child elements.

var qry = from e in xml.Elements()

        select e;



// Add child element to show deferred execuiton.

xml.Add(new XElement("child2"));





foreach(var q in qry)

    Console.Write(q.Name + " ");

    // Print: "child1 child2".

Console.WriteLine();



// Add new child element to show "each time" execution.

xml.Add(new XElement("child3"));



foreach (var q in qry)

    Console.Write(q.Name + " ");

    // Print: "child1 child2 child3".

为了避免多余的处决,您可以缓存查询结果,所使用的toArray()或ToList()扩展方法。我打算使用的结果类型查询完整的类型搜索和类型成员的搜索都,因此在最坏的情况下,类型的查询将被执行两次。为了避免这种情况,我使用的toArray()函数缓存查询结果。
现在,当我们发现的类型,我们可以进行类型的成员搜索。直的方法是使用嵌套的选择:
var members = // For each incoplete types

from type in types

where !type.IsComplete



// Select all type methods that has matched name and signature.

from member in

     type.TypeElement.Element("methodlist").Elements("method")

where member.Element("newname").Value == signature.MemberName &&

      signature.SygEquals(member.Element("signature").Value)



select member;

在这里,我们选择不完整类型的方法和过滤器相匹配的签名物件。这个查询将被编译成这样的:
var members =

// Filter incomplete types.

types.Where(type => !type.IsComplete)



// Flatten all types members in one enumeration.

.SelectMany(

   type => type.TypeElement.Element("methodlist").Elements("method"),

    // Projecting result to temporary anonymous type.

   (type, member) => new { type = type, member = member }   

)



// Filter out type members by signature matching.

.Where(typeMember => 

   typeMember.member.Element("newname").Value == signature.MemberName &&

   signature.SygEquals(typeMember.member.Element("signature").Value)

)



// Select only member XElement from result

.Select(typeMember => typeMember.member);

在这里,我们可以看到一个匿名类型的投影SelectMany调用。在一般情况下,每个类型的数组类型元素包含一个方法的集合,因此它看起来就像一个两维的类型,每个类型都拥有一个方法集合组成的集合。 SelectMany呼叫平坦此收集二维到一维,然后过滤。
这是一般情况下,但在我们的例子中,我们将不得不与大多数集合的一种方法(因为我们的搜索过滤器)类型的集合。因此,我们有一个多余的SelectMany调用一个匿名类型,这将影响性能的投影。我们不能使用一个明确的LINQ语法来解决此问题,但我们可以结合LINQ扩展方法和lambda表达式,以达到预期的效果:
var members = ( // For each incoplete types

 from type in types

 where !type.IsComplete



 // Select single method that mathes name and signature.

 select type.TypeElement.Element("methodlist").Elements("method")

  .SingleOrDefault(member => 

      member.Element("newname").Value == signature.MemberName &&

      signature.SygEquals(member.Element("signature").Value)



   )

).Where(m => m != null);

在这里,我结合LINQ与SingleOrDefault扩展方法的调用,让我删除SelectMany调用和匿名类型的投影选择。最后出结果的默认值的方法调用过滤器 - 这将给予我们如果没有找到一个空的枚举。这里是什么将被编译到:
最后,我们可以根据项目的匿名类型的成员,帮助我们在未来的过程中,查询的结果。
var membersPrj = from member in members

                 select new {

                   ModuleName = member.Parent.Parent.Parent.Element("name").Value,

                   TypeName = member.Parent.Parent.Element("name").Value,

                   MemberName = member.Element("name").Value,

                   Signature = member.Element("signature").Value

                 };

是没有区别的方法和字段搜索,由于统一的签名一流的解决方案的,所以我广义的领域和方法搜索的方法。现在,您可以过程中发现的成员,按照您的意愿,例如,输出到控制台:
foreach (var member in membersPrj) {

    Console.WriteLine("Module:      {0}", member.ModuleName);

    Console.WriteLine("Type:        {0}", member.TypeName);

    Console.WriteLine("Member:      {0}", member.MemberName);

    Console.WriteLine();

}

完整的解决方案,可以在文章的顶部的链接下载。摘要
这就是全部。还有许多事情到做,例如,应用程序可以处理的整个调用栈和可检索DE -混淆的版本也,它的方便一些外部的API,例如,一个命令行或像这样的东西,但此本文的范围。
我还应该提到一些我在开发过程中所面临的问题。首先是因为不能用作方法参数的匿名类型的代码分解,这是很难提供的。另一种是LINQ查询调试是相当困难的(但由于LINQ的垫,并不难,因为它可以)的。所有其他不那么明显,所以我不认为他们值得这里要提到。
本文介绍了我的一个实际使用的LINQ to SQL技术的第一的经验。我希望你喜欢读书,和文章的材料会给你带来一些新的和有益的经验,可以适用于你的练习。

回答

评论会员:melloromg 时间:2012/01/25

评论会员:器Resco开发工具 时间:2012/01/25
梅勒,感谢你的客气话!

伊万??器Resco
评论会员:lanmanck 时间:2012/01/25
来源?对我们是有一些帮助呢? -_-!{ BR}
评论会员:器Resco开发工具 时间:2012/01/25
源代码是被称为器Resco PhotoAssistant ESP解决方案的一部分。有看看这个:{A4}

如果您正在寻找文档,请给我一封电子邮件给伊万(AT)RESCO点净。

的问候,
伊万