From b29bb247cb6fe7e9496a2dd7f900de13a63b5053 Mon Sep 17 00:00:00 2001 From: DickBaker Date: Fri, 14 Jun 2024 18:08:56 +0100 Subject: [PATCH 1/2] this PR answers my earlier Issue #3 also included .editorconfig to standardise repo changes enjoy ! --- .editorconfig | 246 ++++++++++++++++ Delegates.sln | 5 + Delegates/Delegates.csproj | 6 +- Delegates/Guitar.cs | 82 +++--- Delegates/Program.cs | 30 +- TitanicExplorer.Data.Tests/DataTests.cs | 39 ++- .../TitanicExplorer.Data.Tests.csproj | 23 +- TitanicExplorer.Data/Passenger.cs | 75 +++-- .../TitanicExplorer.Data.csproj | 4 +- .../TitanicExplorer.Scripting.Tests.csproj | 21 +- TitanicExplorer.Scripting.Tests/UnitTest1.cs | 137 +++++---- TitanicExplorer.Scripting/ScriptingEngine.cs | 204 ++++++++------ .../TitanicExplorer.Scripting.csproj | 12 +- TitanicExplorer/Pages/Error.cshtml.cs | 30 +- TitanicExplorer/Pages/Index.cshtml | 2 +- TitanicExplorer/Pages/Index.cshtml.cs | 262 ++++++++---------- TitanicExplorer/Pages/Privacy.cshtml.cs | 22 +- TitanicExplorer/Program.cs | 8 +- TitanicExplorer/TitanicExplorer.csproj | 8 +- 19 files changed, 703 insertions(+), 513 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..105733c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,246 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = true +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_collection_expression = when_types_loosely_match +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = false +dotnet_style_allow_statement_immediately_after_block_experimental = true + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = true +csharp_style_var_when_type_is_apparent = true + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = true:suggestion +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_operators = true:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async +csharp_style_prefer_readonly_struct = true +csharp_style_prefer_readonly_struct_member = true + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = true:silent + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = true +csharp_style_prefer_tuple_swap = true +csharp_style_prefer_utf8_string_literals = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable:silent +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:suggestion + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +csharp_style_allow_embedded_statements_on_same_line_experimental = true + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = all +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_labels = one_less_than_current +csharp_indent_switch_labels = true + +# 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 = false +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 + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +[*.{cs,vb}] +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_require_accessibility_modifiers = omit_if_default:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent \ No newline at end of file diff --git a/Delegates.sln b/Delegates.sln index f84c6e7..eb184a3 100644 --- a/Delegates.sln +++ b/Delegates.sln @@ -15,6 +15,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TitanicExplorer.Scripting", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TitanicExplorer.Scripting.Tests", "TitanicExplorer.Scripting.Tests\TitanicExplorer.Scripting.Tests.csproj", "{7D179EC1-554D-49D9-962D-D4C9CDE51A4C}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{452FAC10-9638-43FD-A3E0-A2D45AFEF1CD}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/Delegates/Delegates.csproj b/Delegates/Delegates.csproj index 74abf5c..410fa2a 100644 --- a/Delegates/Delegates.csproj +++ b/Delegates/Delegates.csproj @@ -1,10 +1,10 @@ - + Exe - net6.0 + net8.0 enable enable - + diff --git a/Delegates/Guitar.cs b/Delegates/Guitar.cs index a8b334b..6a783e2 100644 --- a/Delegates/Guitar.cs +++ b/Delegates/Guitar.cs @@ -1,55 +1,47 @@ -namespace Delegates +namespace Delegates; + +/// +/// The pickup situation for the guitar +/// +public enum PickupType +{ + Acoustic, + AcousticElectric, + Electric +} + +/// +/// What kind of strings the guitar has +/// +public enum StringType +{ + Steel, + Nylon +} + +/// +/// Guitars because they're cool +/// +/// +/// Constructor which sets all the properties +/// +/// The broad pickup type +/// Steel string or nylon +/// The name of the guitar +public class Guitar(PickupType pickup, StringType strings, string name) { /// - /// The pickup situation for the guitar + /// Model Name of the guitar /// - public enum PickupType - { - Acoustic, - AcousticElectric, - Electric - } + public string Name { get; set; } = name; /// - /// What kind of strings the guitar has + /// The pickup situation for the guitar /// - public enum StringType - { - Steel, - Nylon - } + public PickupType Pickup { get; set; } = pickup; /// - /// Guitars because they're cool + /// What kind of strings the guitar has /// - public class Guitar - { - /// - /// Constructor which sets all the properties - /// - /// The broad pickup type - /// Steel string or nylon - /// The name of the guitar - public Guitar(PickupType pickup, StringType strings, string name) - { - Pickup = pickup; - Strings = strings; - Name = name; - } - - /// - /// Model Name of the guitar - /// - public string Name { get; set; } - - /// - /// The pickup situation for the guitar - /// - public PickupType Pickup { get; set; } - - /// - /// What kind of strings the guitar has - /// - public StringType Strings { get; set; } - } + public StringType Strings { get; set; } = strings; } diff --git a/Delegates/Program.cs b/Delegates/Program.cs index ddb3edc..db3c7e5 100644 --- a/Delegates/Program.cs +++ b/Delegates/Program.cs @@ -1,25 +1,23 @@ -using System; -using System.Linq.Expressions; +using System.Linq.Expressions; -namespace Delegates +namespace Delegates; + +static class Program { - internal class Program + static void Main() { - static void Main(string[] args) - { - var xExpression = Expression.Parameter(typeof(int), "x"); - var constantExpression = Expression.Constant(12); - var greaterThan = Expression.GreaterThan(xExpression, constantExpression); + ParameterExpression xExpression = Expression.Parameter(typeof(int), "x"); + ConstantExpression constantExpression = Expression.Constant(12); + BinaryExpression greaterThan = Expression.GreaterThan(xExpression, constantExpression); - var constant4Expression = Expression.Constant(4); - var lessThan = Expression.LessThan(xExpression, constant4Expression); + ConstantExpression constant4Expression = Expression.Constant(4); + BinaryExpression lessThan = Expression.LessThan(xExpression, constant4Expression); - var or = Expression.Or(greaterThan, lessThan); + BinaryExpression or = Expression.Or(greaterThan, lessThan); - var expr = Expression.Lambda>(or, false, new List { xExpression, }); - var func = expr.Compile(); + var expr = Expression.Lambda>(or, false, new List { xExpression, }); + Func func = expr.Compile(); - Console.WriteLine(func(2)); - } + Console.WriteLine(func(2)); } } \ No newline at end of file diff --git a/TitanicExplorer.Data.Tests/DataTests.cs b/TitanicExplorer.Data.Tests/DataTests.cs index ac48573..a8638d2 100644 --- a/TitanicExplorer.Data.Tests/DataTests.cs +++ b/TitanicExplorer.Data.Tests/DataTests.cs @@ -1,31 +1,26 @@ -namespace TitanicExplorer.Data.Tests -{ - using Xunit; - using System.IO; - using System.Linq; +using System.IO; +using Xunit; + +namespace TitanicExplorer.Data.Tests; - public class DataTests +public class DataTests +{ + public DataTests() { - public DataTests() - { - this.SampleDataPath = Path.GetTempFileName(); + SampleDataPath = Path.GetTempFileName(); - File.WriteAllText(this.SampleDataPath, Resource.passengers); - } + File.WriteAllText(SampleDataPath, Resource.passengers); + } - public string SampleDataPath - { - get; set; - } + public string SampleDataPath { get; } - [Fact] - public void LoadData() - { - var passengers = Passenger.LoadFromFile(this.SampleDataPath); + [Fact] + public void LoadData() + { + System.Collections.Generic.List passengers = Passenger.LoadFromFile(SampleDataPath); - Assert.Equal(887, passengers.Count()); + Assert.Equal(887, passengers.Count); - Assert.Equal("Mr. Owen Harris Braund", passengers.First().Name); - } + Assert.Equal("Mr. Owen Harris Braund", passengers[0].Name); } } \ No newline at end of file diff --git a/TitanicExplorer.Data.Tests/TitanicExplorer.Data.Tests.csproj b/TitanicExplorer.Data.Tests/TitanicExplorer.Data.Tests.csproj index 370efbf..2e25685 100644 --- a/TitanicExplorer.Data.Tests/TitanicExplorer.Data.Tests.csproj +++ b/TitanicExplorer.Data.Tests/TitanicExplorer.Data.Tests.csproj @@ -1,29 +1,28 @@ - - + + - net6.0 + net8.0 enable - false - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + True @@ -31,12 +30,12 @@ Resource.resx - + ResXFileCodeGenerator Resource.Designer.cs - + diff --git a/TitanicExplorer.Data/Passenger.cs b/TitanicExplorer.Data/Passenger.cs index a789a0f..0746bfd 100644 --- a/TitanicExplorer.Data/Passenger.cs +++ b/TitanicExplorer.Data/Passenger.cs @@ -1,48 +1,47 @@ -namespace TitanicExplorer.Data +namespace TitanicExplorer.Data; + +public class Passenger { - public class Passenger + public enum SexValue { - public enum SexValue - { - Male = 0, - Female = 1 - } + Male = 0, + Female = 1 + } - public bool Survived { get; set; } - public int PClass { get; set; } - public string Name { get; set; } - public SexValue Sex { get; set; } - public decimal Age { get;set; } - public int SiblingsOrSpouse { get; set; } - public int ParentOrChildren { get; set; } - public decimal Fare { get; set; } + public bool Survived { get; set; } + public int PClass { get; set; } + public string Name { get; set; } = default!; + public SexValue Sex { get; set; } + public decimal Age { get; set; } + public int SiblingsOrSpouse { get; set; } + public int ParentOrChildren { get; set; } + public decimal Fare { get; set; } - public static List LoadFromFile(string filePath) - { - var lines = File.ReadAllLines(filePath); + public static List LoadFromFile(string filePath) + { + var lines = File.ReadAllLines(filePath); + + var passengers = new List(); - var passengers = new List(); + foreach (var line in lines) + { + var values = line.Split('\t'); - foreach (var line in lines) + var passenger = new Passenger { - var values = line.Split('\t'); - - var passenger = new Passenger - { - Survived = values[0] == "1", - PClass = int.Parse(values[1]), - Name = values[2], - Sex = values[3] == "male" ? SexValue.Male : SexValue.Female, - Age = decimal.Parse(values[4]), - SiblingsOrSpouse = int.Parse(values[5]), - ParentOrChildren = int.Parse(values[6]), - Fare = decimal.Parse(values[7]) - }; - - passengers.Add(passenger); - } - - return passengers; + Survived = values[0] == "1", + PClass = int.Parse(values[1]), + Name = values[2], + Sex = values[3] == "male" ? SexValue.Male : SexValue.Female, + Age = decimal.Parse(values[4]), + SiblingsOrSpouse = int.Parse(values[5]), + ParentOrChildren = int.Parse(values[6]), + Fare = decimal.Parse(values[7]) + }; + + passengers.Add(passenger); } + + return passengers; } } \ No newline at end of file diff --git a/TitanicExplorer.Data/TitanicExplorer.Data.csproj b/TitanicExplorer.Data/TitanicExplorer.Data.csproj index 132c02c..9af4a6b 100644 --- a/TitanicExplorer.Data/TitanicExplorer.Data.csproj +++ b/TitanicExplorer.Data/TitanicExplorer.Data.csproj @@ -1,7 +1,7 @@ - + - net6.0 + net8.0 enable enable diff --git a/TitanicExplorer.Scripting.Tests/TitanicExplorer.Scripting.Tests.csproj b/TitanicExplorer.Scripting.Tests/TitanicExplorer.Scripting.Tests.csproj index 683961b..a172779 100644 --- a/TitanicExplorer.Scripting.Tests/TitanicExplorer.Scripting.Tests.csproj +++ b/TitanicExplorer.Scripting.Tests/TitanicExplorer.Scripting.Tests.csproj @@ -1,28 +1,27 @@ - + - net6.0 + net8.0 enable - + false - + - - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + diff --git a/TitanicExplorer.Scripting.Tests/UnitTest1.cs b/TitanicExplorer.Scripting.Tests/UnitTest1.cs index 9e4b76b..c2fc892 100644 --- a/TitanicExplorer.Scripting.Tests/UnitTest1.cs +++ b/TitanicExplorer.Scripting.Tests/UnitTest1.cs @@ -1,94 +1,85 @@ using System; using System.Linq.Expressions; -using TitanicExplorer.Scripting; using Xunit; -namespace TitanicExplorer.Scriptings.Tests +namespace TitanicExplorer.Scripting.Tests; + +public class UnitTest1 { - public class UnitTest1 + [Fact] + public void IsPrimeTest() { - [Fact] - public void IsPrime() - { - var value = Expression.Parameter(typeof(int), "value"); + ParameterExpression value = Expression.Parameter(typeof(int), "value"); - var result = ScriptingEngine.IsPrime(value); + Expression result = ScriptingEngine.IsPrime(value); - var expr = Expression.Lambda>(result, value); + var expr = Expression.Lambda>(result, value); - var func = expr.Compile(); + Func func = expr.Compile(); - Assert.False(func(0)); - Assert.False(func(1)); - Assert.True(func(2)); - Assert.True(func(3)); - Assert.False(func(4)); - Assert.True(func(5)); - Assert.False(func(9)); - Assert.False(func(144)); - Assert.True(func(1531)); - } + Assert.False(func(0)); + Assert.False(func(1)); + Assert.True(func(2)); + Assert.True(func(3)); + Assert.False(func(4)); + Assert.True(func(5)); + Assert.False(func(9)); + Assert.False(func(144)); + Assert.True(func(1531)); + } - [Fact] - public void Test() + [Fact] + public void IsPrimeCSTest() + { + Assert.False(ScriptingEngine.IsPrimeCS(0)); + Assert.False(ScriptingEngine.IsPrimeCS(1)); + Assert.True(ScriptingEngine.IsPrimeCS(2)); + Assert.True(ScriptingEngine.IsPrimeCS(3)); + Assert.False(ScriptingEngine.IsPrimeCS(4)); + Assert.True(ScriptingEngine.IsPrimeCS(5)); + Assert.False(ScriptingEngine.IsPrimeCS(9)); + Assert.False(ScriptingEngine.IsPrimeCS(144)); + Assert.True(ScriptingEngine.IsPrimeCS(1531)); + } + + [Fact] + public void Test() + { + static bool func(int value) { - Func func = value => + if (value <= 1) { return false; } + + if (value <= 3) { return true; } + + if (value % 2 == 0) { return false; } + + var i = 3; + var boundary = (int)Math.Floor(Math.Sqrt(value)); + while (i <= boundary) { - bool result; - - if (value <= 1) - { - return false; - } - - if (value == 2) - { - return true; - } - - if ((value % 2) == 0) - { - return false; - } - - var i = 3; - var boundary = (int)Math.Floor(Math.Sqrt((double)value)); - while (true) - { - if (i <= boundary) - { - if ((value % i) == 0) - { - return false; - } - - i += 2; - } - else - { - break; - } - } - - return true; - }; - - Assert.True(func(19)); + if (value % i == 0) { return false; } + + i += 2; + } + + return true; } - [Fact] - public void Factorial() - { - var value = Expression.Parameter(typeof(int)); + Assert.True(func(19)); + } + + [Fact] + public void Factorial() + { + ParameterExpression value = Expression.Parameter(typeof(int)); - var result = ScriptingEngine.Factorial(value); + Expression result = ScriptingEngine.Factorial(value); - var expr = Expression.Lambda>(result, value); + var expr = Expression.Lambda>(result, value); - var func = expr.Compile(); + Func func = expr.Compile(); - Assert.Equal(6, func(3)); - Assert.Equal(120, func(5)); - } + Assert.Equal(6, func(3)); + Assert.Equal(120, func(5)); } } \ No newline at end of file diff --git a/TitanicExplorer.Scripting/ScriptingEngine.cs b/TitanicExplorer.Scripting/ScriptingEngine.cs index d1ca23a..f78da83 100644 --- a/TitanicExplorer.Scripting/ScriptingEngine.cs +++ b/TitanicExplorer.Scripting/ScriptingEngine.cs @@ -1,114 +1,136 @@ -namespace TitanicExplorer.Scripting -{ - using System.Linq.Dynamic.Core; - using System.Linq.Expressions; +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; + +namespace TitanicExplorer.Scripting; - public class ScriptingEngine +public static class ScriptingEngine +{ + public static Expression ExpressionFromString(string value) => + DynamicExpressionParser.ParseLambda(new ParsingConfig(), true, value); + + /// + /// C# high-level code to find if specified number is prime + /// + /// input parameter for testing if prime + /// true if number is prime, false otherwise + /// + /// 1. introduced at [4.10; 1:27] and in making-expression-trees-work-for-you-slides.pdf #25/37, but unfortunately absent in repo + /// - so featured here and unit-tested in TitanicExplorer.Scripting.Tests.UnitTest1.IsPrimeCSTest + /// 2. unfortunately all the juicy "Working with Roslyn" code is also absent [sigh] + /// 3. the short-circuit code tweaked slightly [yeah small-beer I know, but it goaded me], and ditto in IsPrime below + /// + public static bool IsPrimeCS(int number) { - public static Expression ExpressionFromString(string value) - { - return DynamicExpressionParser.ParseLambda(new ParsingConfig(), true, value); - } + if (number <= 1) return false; + if (number <= 3) return true; + if (number % 2 == 0) return false; - public static Expression IsPrime(ParameterExpression value) + var boundary = (int)Math.Floor(Math.Sqrt(number)); + for (var i = 3; i <= boundary; i += 2) { - var label = Expression.Label(); - - var result = Expression.Parameter(typeof(bool), "result"); - - var returnLabel = Expression.Label(typeof(bool)); - - var valueLessThanEqualToOne = Expression.LessThanOrEqual(value, Expression.Constant(1)); - var valueEqualTwo = Expression.Equal(value, Expression.Constant(2)); - var valueModTwoZero = Expression.Equal(Expression.Modulo(value, Expression.Constant(2)), Expression.Constant(0)); - - var sqRt = typeof(Math).GetMethod("Sqrt"); - var floor = typeof(Math).GetMethod("Floor", new Type[] { typeof(double) }); - - var valueSqRt = Expression.Call(null, sqRt, Expression.Convert(value, typeof(double))); + if (number % i == 0) { return false; } + } + return true; + } - var evalFunction = Expression.Convert(Expression.Call(null, floor, valueSqRt), typeof(int)); + public static Expression IsPrime(ParameterExpression value) + { + LabelTarget label = Expression.Label(); - var boundary = Expression.Variable(typeof(int), "boundary"); + ParameterExpression result = Expression.Parameter(typeof(bool), "result"); - var i = Expression.Variable(typeof(int), "i"); + LabelTarget returnLabel = Expression.Label(typeof(bool)); - Expression modBlock = Expression.IfThen( - Expression.Equal(Expression.Modulo(value, i), Expression.Constant(0)), - Expression.Return(returnLabel, Expression.Constant(false)) - ); + BinaryExpression valueLessThanEqualToOne = Expression.LessThanOrEqual(value, Expression.Constant(1)); + BinaryExpression valueLessThanEqualToThree = Expression.LessThanOrEqual(value, Expression.Constant(3)); + BinaryExpression valueModTwoZero = Expression.Equal(Expression.Modulo(value, Expression.Constant(2)), Expression.Constant(0)); - Expression incrementI = Expression.AddAssign(i, Expression.Constant(2)); + System.Reflection.MethodInfo sqRt = typeof(Math).GetMethod("Sqrt")!; + System.Reflection.MethodInfo floor = typeof(Math).GetMethod("Floor", [typeof(double)])!; - BlockExpression block = Expression.Block( - new[] { result, i, boundary }, - Expression.IfThen( - valueLessThanEqualToOne, - Expression.Return(returnLabel, Expression.Constant(false)) - ), - Expression.IfThen( - valueEqualTwo, - Expression.Return(returnLabel, Expression.Constant(true)) - ), - Expression.IfThen( - valueModTwoZero, - Expression.Return(returnLabel, Expression.Constant(false)) - ), + MethodCallExpression valueSqRt = Expression.Call(null, sqRt, Expression.Convert(value, typeof(double))); - Expression.Assign(i, Expression.Constant(3)), - Expression.Assign(boundary, evalFunction), - Expression.Loop( - Expression.IfThenElse - ( - Expression.LessThanOrEqual(i, boundary), - Expression.Block(modBlock, incrementI), - Expression.Break(label) - ), - label - ), - Expression.Return(returnLabel, Expression.Constant(true)), - Expression.Label(returnLabel, Expression.Constant(true)) - ); + UnaryExpression evalFunction = Expression.Convert(Expression.Call(null, floor, valueSqRt), typeof(int)); - return block; - } + ParameterExpression boundary = Expression.Variable(typeof(int), "boundary"); - /// - /// From Microsoft Docs: https://docs.microsoft.com/en-us/dotnet/csharp/expression-trees-building - /// - /// Returns a factorial expression - public static Expression Factorial(ParameterExpression value) - { - ParameterExpression result = Expression.Variable(typeof(int), "result"); + ParameterExpression i = Expression.Variable(typeof(int), "i"); - // Creating a label that represents the return value - LabelTarget label = Expression.Label(typeof(int)); + Expression modBlock = Expression.IfThen( + Expression.Equal(Expression.Modulo(value, i), Expression.Constant(0)), + Expression.Return(returnLabel, Expression.Constant(false)) + ); - var initializeResult = Expression.Assign(result, Expression.Constant(1)); + Expression incrementI = Expression.AddAssign(i, Expression.Constant(2)); - // This is the inner block that performs the multiplication, - // and decrements the value of 'n' - var block = Expression.Block( - Expression.Assign(result, - Expression.Multiply(result, value)), - Expression.PostDecrementAssign(value) - ); + BlockExpression block = Expression.Block( + [result, i, boundary], + Expression.IfThen( + valueLessThanEqualToOne, + Expression.Return(returnLabel, Expression.Constant(false)) + ), + Expression.IfThen( + valueLessThanEqualToThree, + Expression.Return(returnLabel, Expression.Constant(true)) + ), + Expression.IfThen( + valueModTwoZero, + Expression.Return(returnLabel, Expression.Constant(false)) + ), - // Creating a method body. - BlockExpression body = Expression.Block( - new[] { result }, - initializeResult, + Expression.Assign(i, Expression.Constant(3)), + Expression.Assign(boundary, evalFunction), Expression.Loop( - Expression.IfThenElse( - Expression.GreaterThan(value, Expression.Constant(1)), - block, - Expression.Break(label, result) + Expression.IfThenElse + ( + Expression.LessThanOrEqual(i, boundary), + Expression.Block(modBlock, incrementI), + Expression.Break(label) ), label - ) - ); + ), + Expression.Return(returnLabel, Expression.Constant(true)), + Expression.Label(returnLabel, Expression.Constant(true)) + ); - return body; - } + return block; + } + + /// + /// From Microsoft Docs: https://docs.microsoft.com/en-us/dotnet/csharp/expression-trees-building + /// + /// Returns a factorial expression + public static Expression Factorial(ParameterExpression value) + { + ParameterExpression result = Expression.Variable(typeof(int), "result"); + + // Creating a label that represents the return value + LabelTarget label = Expression.Label(typeof(int)); + + BinaryExpression initializeResult = Expression.Assign(result, Expression.Constant(1)); + + // This is the inner block that performs the multiplication, + // and decrements the value of 'n' + BlockExpression block = Expression.Block( + Expression.Assign(result, + Expression.Multiply(result, value)), + Expression.PostDecrementAssign(value) + ); + + // Creating a method body. + BlockExpression body = Expression.Block( + [result], + initializeResult, + Expression.Loop( + Expression.IfThenElse( + Expression.GreaterThan(value, Expression.Constant(1)), + block, + Expression.Break(label, result) + ), + label + ) + ); + + return body; } } \ No newline at end of file diff --git a/TitanicExplorer.Scripting/TitanicExplorer.Scripting.csproj b/TitanicExplorer.Scripting/TitanicExplorer.Scripting.csproj index 4e7adeb..b1dfbcb 100644 --- a/TitanicExplorer.Scripting/TitanicExplorer.Scripting.csproj +++ b/TitanicExplorer.Scripting/TitanicExplorer.Scripting.csproj @@ -1,13 +1,13 @@ - - + + - net6.0 + net8.0 enable enable - + - + - + diff --git a/TitanicExplorer/Pages/Error.cshtml.cs b/TitanicExplorer/Pages/Error.cshtml.cs index 59eed3f..a0292ce 100644 --- a/TitanicExplorer/Pages/Error.cshtml.cs +++ b/TitanicExplorer/Pages/Error.cshtml.cs @@ -1,27 +1,19 @@ +using System.Diagnostics; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; -using System.Diagnostics; -namespace TitanicExplorer.Pages -{ - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - [IgnoreAntiforgeryToken] - public class ErrorModel : PageModel - { - public string? RequestId { get; set; } +namespace TitanicExplorer.Pages; - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); +[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] +[IgnoreAntiforgeryToken] +public class ErrorModel(ILogger logger) : PageModel +{ + public string? RequestId { get; set; } - private readonly ILogger _logger; + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - public ErrorModel(ILogger logger) - { - _logger = logger; - } + public ILogger Logger => logger; - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } - } + public void OnGet() => + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; } \ No newline at end of file diff --git a/TitanicExplorer/Pages/Index.cshtml b/TitanicExplorer/Pages/Index.cshtml index 9c612e5..62785ab 100644 --- a/TitanicExplorer/Pages/Index.cshtml +++ b/TitanicExplorer/Pages/Index.cshtml @@ -66,7 +66,7 @@ - + diff --git a/TitanicExplorer/Pages/Index.cshtml.cs b/TitanicExplorer/Pages/Index.cshtml.cs index 73a31cd..e3c12af 100644 --- a/TitanicExplorer/Pages/Index.cshtml.cs +++ b/TitanicExplorer/Pages/Index.cshtml.cs @@ -1,185 +1,145 @@ -namespace TitanicExplorer.Pages +using System.Linq.Dynamic.Core; +using System.Linq.Expressions; +using AgileObjects.ReadableExpressions; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TitanicExplorer.Data; +using static TitanicExplorer.Data.Passenger; + +namespace TitanicExplorer.Pages; + +public class IndexModel : PageModel { - using Microsoft.AspNetCore.Mvc; - using Microsoft.AspNetCore.Mvc.RazorPages; - using TitanicExplorer.Data; - using System.IO; - using static TitanicExplorer.Data.Passenger; - using System.Linq.Expressions; - using AgileObjects.ReadableExpressions; - using System.Linq.Dynamic.Core; - - public class IndexModel : PageModel + public IndexModel(ILogger logger) { - private readonly ILogger _logger; + Logger = logger; - public IndexModel(ILogger logger) - { - _logger = logger; + var sampleDataPath = Path.GetTempFileName(); - var sampleDataPath = Path.GetTempFileName(); + System.IO.File.WriteAllText(sampleDataPath, DataFiles.passengers); - System.IO.File.WriteAllText(sampleDataPath, DataFiles.passengers); + Passengers = Passenger.LoadFromFile(sampleDataPath); + } + public ILogger Logger { get; } - this.Passengers = Passenger.LoadFromFile(sampleDataPath); - } + public IEnumerable Passengers + { + get; private set; + } - public IEnumerable Passengers - { - get; private set; - } + public void OnGet() + { } - public void OnGet() - { + public string? Query { get; set; } - } - - public string query { get; set; } + public void OnPost() + { + var survived = Request.Form["survived"] != "" ? ParseSurvived(Request.Form["survived"]!) : null; + var pClass = ParseNullInt(Request.Form["pClass"]!); + SexValue? sex = Request.Form["sex"] != "" ? ParseSex(Request.Form["sex"]!) : null; + var age = ParseNullDecimal(Request.Form["age"]!); + var minimumFare = ParseNullDecimal(Request.Form["minimumFare"]!); + Query = Request.Form["query"]!; + + Passengers = FilterPassengers(survived, pClass, sex, age, minimumFare); + } - public void OnPost() - { - var survived = Request.Form["survived"]!= "" ? ParseSurvived(Request.Form["survived"]) : null; - var pClass = ParseNullInt(Request.Form["pClass"]); - var sex = Request.Form["sex"] != "" ? ParseSex(Request.Form["sex"]) : null; - var age = ParseNullDecimal(Request.Form["age"]); - var minimumFare = ParseNullDecimal(Request.Form["minimumFare"]); - this.query = Request.Form["query"]; - - this.Passengers = FilterPassengers(survived, pClass, sex, age, minimumFare); - } + IEnumerable FilterPassengers(bool? survived, int? pClass, SexValue? sex, decimal? age, decimal? minimumFare) + { + Expression? currentExpression = null; - private IEnumerable FilterPassengers(bool? survived, int? pClass, SexValue? sex, decimal? age, decimal? minimumFare) + if (!string.IsNullOrEmpty(Query)) { - Expression? currentExpression = null; - - if (!string.IsNullOrEmpty(this.query)) - { - var expr = DynamicExpressionParser.ParseLambda(new ParsingConfig(), true, this.query); - - var func = expr.Compile(); - - return this.Passengers.Where(func); - } - - var passengerParameter = Expression.Parameter(typeof(Passenger)); + Expression> expr = DynamicExpressionParser.ParseLambda(new ParsingConfig(), true, Query); - if (survived != null) - { - currentExpression = CreateExpression(survived.Value, null, "Survived", passengerParameter); - } + Func func = expr.Compile(); - if (pClass != null) - { - currentExpression = CreateExpression(pClass.Value, currentExpression, "PClass", passengerParameter); - } - - if (sex != null) - { - currentExpression = CreateExpression(sex.Value, currentExpression, "Sex", passengerParameter); - } - - if (age != null) - { - currentExpression = CreateExpression(age.Value, currentExpression, "Age", passengerParameter); - } - - if (minimumFare != null) - { - currentExpression = CreateExpression(minimumFare.Value, currentExpression, "Fare", passengerParameter, ">"); - } - - if (currentExpression != null) - { - var expr = Expression.Lambda>(currentExpression, false, new List { passengerParameter }); - var func = expr.Compile(); - - this.query = expr.ToReadableString(); + return Passengers.Where(func); + } - this.Passengers = this.Passengers.Where(func); - } + ParameterExpression passengerParameter = Expression.Parameter(typeof(Passenger)); - return this.Passengers; + if (survived != null) + { + currentExpression = CreateExpression(survived.Value, null, "Survived", passengerParameter); } - /// - /// Aggregates an expression with a property and an operator - /// - /// The type of the parameter - /// The constant value to use in the expression - /// The expression to aggregate with, if any - /// The name of the property to call on the objectParameter - /// The parameter for the object for evaluation - /// A string of the operator to use - /// - private static Expression CreateExpression(T value, Expression? currentExpression, string propertyName, ParameterExpression objectParameter, string operatorType = "=") + if (pClass != null) { - var valueToTest = Expression.Constant(value); - - var propertyToCall = Expression.Property(objectParameter, propertyName); - - Expression operatorExpression; - - switch (operatorType) - { - case ">": - operatorExpression = Expression.GreaterThan(propertyToCall, valueToTest); - break; - case "<": - operatorExpression = Expression.LessThan(propertyToCall, valueToTest); - break; - case ">=": - operatorExpression = Expression.GreaterThanOrEqual(propertyToCall, valueToTest); - break; - case "<=": - operatorExpression = Expression.LessThanOrEqual(propertyToCall, valueToTest); - break; - default: - operatorExpression = Expression.Equal(propertyToCall, valueToTest); - break; - } - - if (currentExpression == null) - { - currentExpression = operatorExpression; - } - else - { - var previousExpression = currentExpression; - - currentExpression = Expression.And(previousExpression, operatorExpression); - } - - return currentExpression; + currentExpression = CreateExpression(pClass.Value, currentExpression, "PClass", passengerParameter); } - public decimal? ParseNullDecimal(string value) + if (sex != null) { - if (decimal.TryParse(value, out decimal result)) - { - return result; - } - - return null; + currentExpression = CreateExpression(sex.Value, currentExpression, "Sex", passengerParameter); } - public int? ParseNullInt(string value) + if (age != null) { - if (int.TryParse(value, out int result)) - { - return result; - } - - return null; + currentExpression = CreateExpression(age.Value, currentExpression, "Age", passengerParameter); } - public SexValue? ParseSex(string value) + if (minimumFare != null) { - return value == "male" ? SexValue.Male : SexValue.Female; + currentExpression = CreateExpression(minimumFare.Value, currentExpression, "Fare", passengerParameter, ">"); } - public bool? ParseSurvived(string value) + if (currentExpression != null) { - return value == "Survived" ? true : false; + var expr = Expression.Lambda>(currentExpression, false, new List { passengerParameter }); + Func func = expr.Compile(); + + Query = expr.ToReadableString(); + + Passengers = Passengers.Where(func); } + + return Passengers; + } + + /// + /// Aggregates an expression with a property and an operator + /// + /// The type of the parameter + /// The constant value to use in the expression + /// The expression to aggregate with, if any + /// The name of the property to call on the objectParameter + /// The parameter for the object for evaluation + /// A string of the operator to use + /// + static Expression CreateExpression(T value, Expression? currentExpression, string propertyName, ParameterExpression objectParameter, string operatorType = "=") + { + ConstantExpression valueToTest = Expression.Constant(value); + + MemberExpression propertyToCall = Expression.Property(objectParameter, propertyName); + Expression operatorExpression = operatorType switch + { + ">" => Expression.GreaterThan(propertyToCall, valueToTest), + "<" => Expression.LessThan(propertyToCall, valueToTest), + ">=" => Expression.GreaterThanOrEqual(propertyToCall, valueToTest), + "<=" => Expression.LessThanOrEqual(propertyToCall, valueToTest), + _ => Expression.Equal(propertyToCall, valueToTest), + }; + + return currentExpression == null + ? operatorExpression + : Expression.And(currentExpression, operatorExpression); } + + public decimal? ParseNullDecimal(string value) => + decimal.TryParse(value, out var result) + ? result + : null; + + public int? ParseNullInt(string value) => + int.TryParse(value, out var result) + ? result + : null; + + public SexValue? ParseSex(string value) => + value == "male" + ? SexValue.Male + : SexValue.Female; + + public bool? ParseSurvived(string value) => + value == "Survived"; } \ No newline at end of file diff --git a/TitanicExplorer/Pages/Privacy.cshtml.cs b/TitanicExplorer/Pages/Privacy.cshtml.cs index 1f05d19..887ed1d 100644 --- a/TitanicExplorer/Pages/Privacy.cshtml.cs +++ b/TitanicExplorer/Pages/Privacy.cshtml.cs @@ -1,19 +1,11 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; -namespace TitanicExplorer.Pages -{ - public class PrivacyModel : PageModel - { - private readonly ILogger _logger; +namespace TitanicExplorer.Pages; - public PrivacyModel(ILogger logger) - { - _logger = logger; - } +public class PrivacyModel(ILogger logger) : PageModel +{ + public ILogger Logger => logger; - public void OnGet() - { - } - } + public void OnGet() + { } } \ No newline at end of file diff --git a/TitanicExplorer/Program.cs b/TitanicExplorer/Program.cs index bc275e4..3530326 100644 --- a/TitanicExplorer/Program.cs +++ b/TitanicExplorer/Program.cs @@ -1,16 +1,16 @@ -var builder = WebApplication.CreateBuilder(args); +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); -var app = builder.Build(); +WebApplication app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { - app.UseExceptionHandler("/Error"); + _ = app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); + _ = app.UseHsts(); } app.UseHttpsRedirection(); diff --git a/TitanicExplorer/TitanicExplorer.csproj b/TitanicExplorer/TitanicExplorer.csproj index 23119ae..017d2ad 100644 --- a/TitanicExplorer/TitanicExplorer.csproj +++ b/TitanicExplorer/TitanicExplorer.csproj @@ -1,14 +1,14 @@ - + - net6.0 + net8.0 enable enable - - + + From a10d18bd7ab49ed9f038a38e80dc4c655e69fbe9 Mon Sep 17 00:00:00 2001 From: DickBaker Date: Fri, 14 Jun 2024 19:14:48 +0100 Subject: [PATCH 2/2] IDE0290 carries forward any ctor comments which ain't too clever if the "primary ctor" at class level has usurped the original ctor. I have learnt another thing today, so "every little helps" [slogan for our Tesco superstores] --- Delegates/Guitar.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Delegates/Guitar.cs b/Delegates/Guitar.cs index 6a783e2..593f0a2 100644 --- a/Delegates/Guitar.cs +++ b/Delegates/Guitar.cs @@ -22,9 +22,6 @@ public enum StringType /// /// Guitars because they're cool /// -/// -/// Constructor which sets all the properties -/// /// The broad pickup type /// Steel string or nylon /// The name of the guitar