Skip to content

Commit

Permalink
Optimize performance of IncludeMemberByPathSelectionRule (#969)
Browse files Browse the repository at this point in the history
  • Loading branch information
jnyrup committed Nov 17, 2018
1 parent 383ed1d commit fe56239
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 21 deletions.
41 changes: 23 additions & 18 deletions Src/FluentAssertions/Common/MemberPath.cs
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace FluentAssertions.Common
Expand All @@ -12,47 +11,53 @@ internal class MemberPath
{
private readonly Type declaringType;
private readonly string dottedPath;
private readonly List<string> segments = new List<string>();

private string[] segments;

public MemberPath(Type declaringType, string dottedPath)
{
this.declaringType = declaringType;
this.dottedPath = dottedPath;
segments.AddRange(Segmentize(dottedPath));
}

public bool IsParentOrChildOf(string candidate)
public bool IsParentOrChildOf(MemberPath candidate)
{
return IsParent(candidate) || IsChild(candidate);
}

public bool IsSameAs(string candidate, Type memberDeclaringType)
public bool IsSameAs(MemberPath candidate)
{
string[] candidateSegments = Segmentize(candidate);
if (candidate.declaringType != declaringType)
{
return false;
}

string[] segments = GetSegments();
string[] candidateSegments = candidate.GetSegments();

return memberDeclaringType == declaringType && candidateSegments.SequenceEqual(segments);
return candidateSegments.SequenceEqual(segments);
}

private bool IsChild(string candidate)
private bool IsChild(MemberPath candidate)
{
string[] candidateSegments = Segmentize(candidate);
string[] segments = GetSegments();
string[] candidateSegments = candidate.GetSegments();

return candidateSegments.Length > segments.Count &&
candidateSegments.Take(segments.Count).SequenceEqual(segments);
return candidateSegments.Length > segments.Length &&
candidateSegments.Take(segments.Length).SequenceEqual(segments);
}

private bool IsParent(string candidate)
private bool IsParent(MemberPath candidate)
{
string[] candidateSegments = Segmentize(candidate);
string[] segments = GetSegments();
string[] candidateSegments = candidate.GetSegments();

return candidateSegments.Length < segments.Count
return candidateSegments.Length < segments.Length
&& candidateSegments.SequenceEqual(segments.Take(candidateSegments.Length));
}

private static string[] Segmentize(string dottedPath)
{
return dottedPath.Split(new[] { '.', '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
}
private string[] GetSegments() =>
segments ?? (segments = dottedPath.Split(new[] { '.', '[', ']' }, StringSplitOptions.RemoveEmptyEntries));

public override string ToString()
{
Expand Down
Expand Up @@ -22,7 +22,7 @@ public ExcludeMemberByPathSelectionRule(MemberPath pathToExclude)
string currentPath, IMemberInfo context)
{
return selectedMembers
.Where(memberInfo => !memberToExclude.IsSameAs(currentPath.Combine(memberInfo.Name), memberInfo.DeclaringType))
.Where(memberInfo => !memberToExclude.IsSameAs(new MemberPath(memberInfo.DeclaringType, currentPath.Combine(memberInfo.Name))))
.ToArray();
}

Expand Down
Expand Up @@ -25,8 +25,8 @@ public IncludeMemberByPathSelectionRule(MemberPath pathToInclude)
{
var matchingMembers =
from member in context.RuntimeType.GetNonPrivateMembers()
let memberPath = currentPath.Combine(member.Name)
where memberToInclude.IsSameAs(memberPath, member.DeclaringType) ||
let memberPath = new MemberPath(member.DeclaringType, currentPath.Combine(member.Name))
where memberToInclude.IsSameAs(memberPath) ||
memberToInclude.IsParentOrChildOf(memberPath)
select member;

Expand Down

0 comments on commit fe56239

Please sign in to comment.