diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..969cbdc
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,237 @@
+# Remove the line below if you want to inherit .editorconfig settings from higher directories
+root = true
+
+# Don't use tabs for indentation.
+[*]
+indent_style = space
+# (Please don't specify an indent_size here; that has too many unintended consequences.)
+
+# Code files
+[*.{cs,csx,vb,vbx}]
+indent_size = 4
+insert_final_newline = false
+charset = utf-8-bom
+end_of_line = crlf
+
+# XML project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
+indent_size = 2
+
+# XML config files
+[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
+
+# JSON files
+[*.json]
+indent_size = 2
+
+[*.{yaml,yml}]
+indent_size = 2
+
+# Powershell files
+[*.ps1]
+indent_size = 2
+
+# sql files
+[*.sql]
+indent_size = 2
+
+# Shell script files
+[*.sh]
+end_of_line = lf
+indent_size = 2
+
+##############################
+# Dotnet code style settings #
+##############################
+[*.{cs,vb}]
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:refactoring
+dotnet_style_qualification_for_property = false:refactoring
+dotnet_style_qualification_for_method = false:refactoring
+dotnet_style_qualification_for_event = false:refactoring
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# Non-private static fields are PascalCase
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
+
+dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
+dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
+
+dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
+
+# Non-private readonly fields are PascalCase
+dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
+dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
+
+dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
+dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly
+
+dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
+
+# Constants are PascalCase
+dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
+dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
+
+dotnet_naming_symbols.constants.applicable_kinds = field, local
+dotnet_naming_symbols.constants.required_modifiers = const
+
+dotnet_naming_style.constant_style.capitalization = pascal_case
+
+# Internal or Private static fields are camelCase and start with s_
+dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
+dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
+
+dotnet_naming_symbols.static_fields.applicable_kinds = field
+dotnet_naming_symbols.static_fields.applicable_accessibilities = internal, private
+dotnet_naming_symbols.static_fields.required_modifiers = static
+
+dotnet_naming_style.static_field_style.capitalization = camel_case
+dotnet_naming_style.static_field_style.required_prefix = s_
+
+# Instance fields are camelCase and start with _
+dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+
+dotnet_naming_symbols.instance_fields.applicable_kinds = field
+
+dotnet_naming_style.instance_field_style.capitalization = camel_case
+dotnet_naming_style.instance_field_style.required_prefix = _
+
+# Locals and parameters are camelCase
+dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
+dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
+
+dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
+
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+
+# Local functions are PascalCase
+dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+
+dotnet_naming_style.local_function_style.capitalization = pascal_case
+
+# By default, name items with PascalCase
+dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
+dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
+
+dotnet_naming_symbols.all_members.applicable_kinds = *
+
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+##############################
+# CSharp code style settings #
+##############################
+[*.cs]
+# IDE0160: Convert to file-scoped namespace
+# csharp_style_namespace_declarations = file_scoped:warning
+csharp_style_namespace_declarations = block_scoped:warning
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = true:suggestion
+
+# Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = do_not_ignore
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Blocks are allowed
+csharp_prefer_braces = true:silent
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = none
+
+## Not needed when nullable references is enabled
+# CA1062: Validate arguments of public methods
+dotnet_diagnostic.CA1062.severity = none
+
+# CA1716: Identifiers should not match keywords
+dotnet_diagnostic.CA1716.severity = none
+
+# Workaround for https://github.com/dotnet/roslyn-analyzers/issues/5628
+[Program.cs]
+dotnet_diagnostic.ca1812.severity = none
\ No newline at end of file
diff --git a/LambdaCompare.sln b/LambdaCompare.sln
index 06684a0..4e01cc7 100644
--- a/LambdaCompare.sln
+++ b/LambdaCompare.sln
@@ -1,14 +1,15 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26403.7
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33414.496
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neleus.LambdaCompare", "Neleus.LambdaCompare\Neleus.LambdaCompare.csproj", "{28179CB7-80D1-4F8C-B171-97DABAB7C874}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neleus.LambdaCompare", "Neleus.LambdaCompare\Neleus.LambdaCompare.csproj", "{28179CB7-80D1-4F8C-B171-97DABAB7C874}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neleus.LambdaCompare.Tests", "Neleus.LambdaCompare.Tests\Neleus.LambdaCompare.Tests.csproj", "{D5556DE2-1758-4EF1-9835-3807E9DED85F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neleus.LambdaCompare.Tests", "Neleus.LambdaCompare.Tests\Neleus.LambdaCompare.Tests.csproj", "{D5556DE2-1758-4EF1-9835-3807E9DED85F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{79CD7955-3850-4C9A-8D11-1322ED8FAF4C}"
ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
LICENSE = LICENSE
README.md = README.md
EndProjectSection
diff --git a/Neleus.LambdaCompare.Tests/Neleus.LambdaCompare.Tests.csproj b/Neleus.LambdaCompare.Tests/Neleus.LambdaCompare.Tests.csproj
index 0a5b7a0..7cf70b7 100644
--- a/Neleus.LambdaCompare.Tests/Neleus.LambdaCompare.Tests.csproj
+++ b/Neleus.LambdaCompare.Tests/Neleus.LambdaCompare.Tests.csproj
@@ -1,24 +1,24 @@
- netcoreapp1.0;netcoreapp2.0;net461
+ net4.6.2;net6.0;net7.0
Neleus.LambdaCompare.Tests
Neleus.LambdaCompare.Tests
false
-
-
-
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
-
-
-
diff --git a/Neleus.LambdaCompare.Tests/Tests.cs b/Neleus.LambdaCompare.Tests/Tests.cs
index dc85558..33c315e 100644
--- a/Neleus.LambdaCompare.Tests/Tests.cs
+++ b/Neleus.LambdaCompare.Tests/Tests.cs
@@ -1,63 +1,149 @@
-using System;
+using System;
using System.Globalization;
using System.Linq.Expressions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Xunit;
+using FluentAssertions;
+using System.Collections.Generic;
+using System.Reflection;
namespace Neleus.LambdaCompare.Tests
{
- [TestClass]
public class Tests
{
- [TestMethod]
+ [Fact]
public void BasicConst()
{
var const1 = 25;
- var f1 = (Expression>) ((first, second) =>
+ var f1 = (Expression>)((first, second) =>
$"{(first + const1).ToString(CultureInfo.InvariantCulture)}{first + second}{"some const value".ToUpper()}{const1}");
var const2 = "some const value";
var const3 = "{0}{1}{2}{3}";
- var f2 = (Expression>) ((i, s) =>
+ var f2 = (Expression>)((i, s) =>
string.Format(const3, (i + 25).ToString(CultureInfo.InvariantCulture), i + s, const2.ToUpper(), 25));
- Assert.IsTrue(Lambda.Eq(f1, f2));
+ Lambda.Eq(f1, f2).Should().BeTrue();
}
- [TestMethod]
+ [Fact]
public void PropAndMethodCall()
{
- var f1 = (Expression>) (arg1 => Uri.IsWellFormedUriString(arg1.ToString(), UriKind.Absolute));
- var f2 = (Expression>) (u => Uri.IsWellFormedUriString(u.ToString(), UriKind.Absolute));
+ var f1 = (Expression>)(arg1 => Uri.IsWellFormedUriString(arg1.ToString(), UriKind.Absolute));
+ var f2 = (Expression>)(u => Uri.IsWellFormedUriString(u.ToString(), UriKind.Absolute));
- Assert.IsTrue(Lambda.Eq(f1, f2));
+ Lambda.Eq(f1, f2).Should().BeTrue();
}
- [TestMethod]
+ [Fact]
public void MemberInitWithConditional()
{
var port = 443;
- var f1 = (Expression>) (x => new UriBuilder(x)
+ var f1 = (Expression>)(x => new UriBuilder(x)
{
Port = port,
Host = string.IsNullOrEmpty(x.Host) ? "abc" : "def"
});
var isSecure = true;
- var f2 = (Expression>) (u => new UriBuilder(u)
+ var f2 = (Expression>)(u => new UriBuilder(u)
{
Host = string.IsNullOrEmpty(u.Host) ? "abc" : "def",
Port = isSecure ? 443 : 80
});
- Assert.IsTrue(Lambda.Eq(f1, f2));
+ Lambda.Eq(f1, f2).Should().BeTrue();
}
- [TestMethod, Ignore]
- public void AnonymousType()
+ [Fact]
+ public void AnonymousType_Not_Supported()
{
- var f1 = (Expression>) (x => new { Port = 443, x.Host, Addr = x.AbsolutePath });
- var f2 = (Expression>) (u => new { u.Host, Port = 443, Addr = u.AbsolutePath });
- Assert.Inconclusive("Anonymous Types are not supported");
+ var f1 = (Expression>)(x => new { Port = 443, x.Host, Addr = x.AbsolutePath });
+ var f2 = (Expression>)(u => new { u.Host, Port = 443, Addr = u.AbsolutePath });
+
+ var sut = (Func)(() => Lambda.Eq(f1, f2));
+
+ sut.Should()
+ .Throw()
+ .WithMessage("Comparison of Anonymous Types is not supported");
+ }
+
+ [Fact]
+ public void Nulls_are_compared_correctly()
+ {
+ var f1 = (Expression>)(_ => "");
+ var f2 = (Expression>)(null);
+ var f3 = (Expression>)(null);
+
+ Lambda.Eq(f1, f2).Should().BeFalse();
+ Lambda.Eq(f2, f3).Should().BeTrue();
+ }
+
+ [Fact]
+ public void Calculations_are_compared_correctly()
+ {
+ var f1 = (Expression>)(_ => 1 + 2);
+ var f2 = (Expression>)(_ => 3);
+
+ Lambda.Eq(f1, f2).Should().BeTrue();
+ }
+
+ [Fact]
+ public void Member_init_expressions_are_compared_correctly()
+ {
+ var addMethod = typeof(List).GetTypeInfo().GetDeclaredMethod("Add");
+
+ var bindingMessages = Expression.ListBind(
+ typeof(Node).GetProperty("Messages"),
+ Expression.ElementInit(addMethod, Expression.Constant("Constant1"))
+ );
+
+ var bindingDescriptions = Expression.ListBind(
+ typeof(Node).GetProperty("Descriptions"),
+ Expression.ElementInit(addMethod, Expression.Constant("Constant2"))
+ );
+
+ Expression e1 = Expression.MemberInit(
+ Expression.New(typeof(Node)),
+ new List { bindingMessages }
+ );
+
+ Expression e2 = Expression.MemberInit(
+ Expression.New(typeof(Node)),
+ new List { bindingMessages, bindingDescriptions }
+ );
+
+ Lambda.ExpressionsEqual(e1, e2).Should().BeFalse();
+ Lambda.ExpressionsEqual(e1, e1).Should().BeTrue();
+ }
+
+ [Fact]
+ public void Default_expressions_are_compared_correctly()
+ {
+ Expression e1 = Expression.Default(typeof(int));
+ Expression e2 = Expression.Default(typeof(int));
+ Expression e3 = Expression.Default(typeof(string));
+
+ Lambda.ExpressionsEqual(e1, e2).Should().BeTrue();
+ Lambda.ExpressionsEqual(e1, e3).Should().BeFalse();
+ Lambda.ExpressionsEqual(e1, e1).Should().BeTrue();
+ }
+
+ [Fact]
+ public void Array_constant_expressions_are_compared_correctly()
+ {
+ var e1 = Expression.Constant(new[] { 1, 2, 3 });
+ var e2 = Expression.Constant(new[] { 1, 2, 3 });
+ var e3 = Expression.Constant(new[] { 1, 2, 4 });
+
+ Lambda.ExpressionsEqual(e1, e2).Should().BeTrue();
+ Lambda.ExpressionsEqual(e1, e3).Should().BeFalse();
+ }
+
+ private class Node
+ {
+ public List Messages { set; get; }
+
+ public List Descriptions { set; get; }
}
}
-}
+}
\ No newline at end of file
diff --git a/Neleus.LambdaCompare/Comparer.cs b/Neleus.LambdaCompare/Comparer.cs
index 7e06a4f..afe33b2 100644
--- a/Neleus.LambdaCompare/Comparer.cs
+++ b/Neleus.LambdaCompare/Comparer.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -16,10 +16,14 @@ public static bool ExpressionsEqual(Expression x, Expression y, LambdaExpression
if (x == null || y == null) return false;
var valueX = TryCalculateConstant(x);
- var valueY = TryCalculateConstant(y);
-
- if (valueX.IsDefined && valueY.IsDefined)
- return ValuesEqual(valueX.Value, valueY.Value);
+ if (valueX.IsDefined)
+ {
+ var valueY = TryCalculateConstant(y);
+ if (valueY.IsDefined)
+ {
+ return ValuesEqual(valueX.Value, valueY.Value);
+ }
+ }
if (x.NodeType != y.NodeType
|| x.Type != y.Type)
@@ -29,87 +33,78 @@ public static bool ExpressionsEqual(Expression x, Expression y, LambdaExpression
return false;
}
- if (x is LambdaExpression)
+ if (x is LambdaExpression lx)
{
- var lx = (LambdaExpression)x;
var ly = (LambdaExpression)y;
var paramsX = lx.Parameters;
var paramsY = ly.Parameters;
return CollectionsEqual(paramsX, paramsY, lx, ly) && ExpressionsEqual(lx.Body, ly.Body, lx, ly);
}
- if (x is MemberExpression)
+ else if (x is MemberExpression mex)
{
- var mex = (MemberExpression)x;
var mey = (MemberExpression)y;
return Equals(mex.Member, mey.Member) && ExpressionsEqual(mex.Expression, mey.Expression, rootX, rootY);
}
- if (x is BinaryExpression)
+ else if (x is BinaryExpression bx)
{
- var bx = (BinaryExpression)x;
var by = (BinaryExpression)y;
return bx.Method == by.Method && ExpressionsEqual(bx.Left, by.Left, rootX, rootY) && ExpressionsEqual(bx.Right, by.Right, rootX, rootY);
}
- if (x is UnaryExpression)
+ else if (x is UnaryExpression ux)
{
- var ux = (UnaryExpression)x;
var uy = (UnaryExpression)y;
return ux.Method == uy.Method && ExpressionsEqual(ux.Operand, uy.Operand, rootX, rootY);
}
- if (x is ParameterExpression)
+ else if (x is ParameterExpression px)
{
- var px = (ParameterExpression)x;
var py = (ParameterExpression)y;
return rootX.Parameters.IndexOf(px) == rootY.Parameters.IndexOf(py);
}
- if (x is MethodCallExpression)
+ else if (x is MethodCallExpression mcx)
{
- var cx = (MethodCallExpression)x;
- var cy = (MethodCallExpression)y;
- return cx.Method == cy.Method
- && ExpressionsEqual(cx.Object, cy.Object, rootX, rootY)
- && CollectionsEqual(cx.Arguments, cy.Arguments, rootX, rootY);
+ var mcy = (MethodCallExpression)y;
+ return mcx.Method == mcy.Method
+ && ExpressionsEqual(mcx.Object, mcy.Object, rootX, rootY)
+ && CollectionsEqual(mcx.Arguments, mcy.Arguments, rootX, rootY);
}
- if (x is MemberInitExpression)
+ else if (x is MemberInitExpression mix)
{
- var mix = (MemberInitExpression)x;
var miy = (MemberInitExpression)y;
return ExpressionsEqual(mix.NewExpression, miy.NewExpression, rootX, rootY)
&& MemberInitsEqual(mix.Bindings, miy.Bindings, rootX, rootY);
}
- if (x is NewArrayExpression)
+ else if (x is NewArrayExpression nax)
{
- var nx = (NewArrayExpression)x;
- var ny = (NewArrayExpression)y;
- return CollectionsEqual(nx.Expressions, ny.Expressions, rootX, rootY);
+ var nay = (NewArrayExpression)y;
+ return CollectionsEqual(nax.Expressions, nay.Expressions, rootX, rootY);
}
- if (x is NewExpression)
+ else if (x is NewExpression nx)
{
- var nx = (NewExpression)x;
var ny = (NewExpression)y;
return Equals(nx.Constructor, ny.Constructor)
&& CollectionsEqual(nx.Arguments, ny.Arguments, rootX, rootY)
- && (nx.Members == null && ny.Members == null
- || nx.Members != null && ny.Members != null && CollectionsEqual(nx.Members, ny.Members));
+ && ((nx.Members == null && ny.Members == null)
+ || (nx.Members != null && ny.Members != null && CollectionsEqual(nx.Members, ny.Members)));
}
- if (x is ConditionalExpression)
+ else if (x is ConditionalExpression cx)
{
- var cx = (ConditionalExpression)x;
var cy = (ConditionalExpression)y;
return ExpressionsEqual(cx.Test, cy.Test, rootX, rootY)
&& ExpressionsEqual(cx.IfFalse, cy.IfFalse, rootX, rootY)
&& ExpressionsEqual(cx.IfTrue, cy.IfTrue, rootX, rootY);
}
+ else if (x is DefaultExpression)
+ {
+ return true;
+ }
throw new NotImplementedException(x.ToString());
}
private static bool IsAnonymousType(Type type)
{
- var hasCompilerGeneratedAttribute = type.GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any();
- var nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
- var isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
-
- return isAnonymousType;
+ return type.FullName.Contains("AnonymousType") &&
+ type.GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any();
}
private static bool MemberInitsEqual(ICollection bx, ICollection by, LambdaExpression rootX, LambdaExpression rootY)
@@ -134,47 +129,48 @@ private static bool ValuesEqual(object x, object y)
{
if (ReferenceEquals(x, y))
return true;
- if (x is ICollection && y is ICollection)
- return CollectionsEqual((ICollection)x, (ICollection)y);
+ if (x is ICollection collectionX && y is ICollection collectionY)
+ return CollectionsEqual(collectionX, collectionY);
return Equals(x, y);
}
private static ConstantValue TryCalculateConstant(Expression e)
{
- if (e is ConstantExpression)
- return new ConstantValue(true, ((ConstantExpression)e).Value);
- if (e is MemberExpression)
+ if (e is ConstantExpression constantExpression)
+ {
+ return new ConstantValue(true, constantExpression.Value);
+ }
+ else if (e is MemberExpression memberExpression)
{
- var me = (MemberExpression)e;
- var parentValue = TryCalculateConstant(me.Expression);
+ var parentValue = TryCalculateConstant(memberExpression.Expression);
if (parentValue.IsDefined)
{
var result =
- me.Member is FieldInfo
- ? ((FieldInfo)me.Member).GetValue(parentValue.Value)
- : ((PropertyInfo)me.Member).GetValue(parentValue.Value);
+ memberExpression.Member is FieldInfo info
+ ? info.GetValue(parentValue.Value)
+ : ((PropertyInfo)memberExpression.Member).GetValue(parentValue.Value);
return new ConstantValue(true, result);
}
}
- if (e is NewArrayExpression)
+ else if (e is NewArrayExpression newArrayExpression)
{
- var ae = ((NewArrayExpression)e);
- var result = ae.Expressions.Select(TryCalculateConstant);
+ var result = newArrayExpression.Expressions.Select(TryCalculateConstant);
if (result.All(i => i.IsDefined))
- return new ConstantValue(true, result.Select(i => i.Value).ToArray