Refactoring code with the Extract method - c#

In my application, we have a class which generates information within a database as static centralised data. This class is called 'GenerateOwner'. Within this class we are creating multiple entries of type 'FieldValidation'.
FieldValidation swedishFieldValidation1 = new FieldValidation
{
IsRequired = false,
DataType = "String",
Length = 0,
Min = 0,
Max = 255,
FieldValidationType = _bancPaydatabase.FieldValidationTypes.FirstOrDefault(o => o.FieldName == "InvoiceNumber"),
IsVisible = true,
Owner_Country = swedishOwnerCountry
};
FieldValidation swedishFieldValidation2 = new FieldValidation
{
IsRequired = false,
DataType = "String",
Length = 0,
Min = 0,
Max = 255,
FieldValidationType = _bancPaydatabase.FieldValidationTypes.FirstOrDefault(o => o.FieldName == "InvoiceTypeId"),
IsVisible = true,
Owner_Country = swedishOwnerCountry
};
And so on. There are about 20 or so entries all very much similar. My question is, how would I best refactor this code to prevent duplicating the same entries over and over? I have been pointed towards the Extract method, but I am unsure of how to implement this in my code. Thanks in advance.

Extract method is a refactoring method that extracts code into its own method. If the extracted part needs parameters they are passed as parameters to the method.
In your code the code is exactly the same except for the field name; The field name would be a parameter to your method.
The result would look like this:
private FieldValidation CreateFieldValidation(string fieldName)
{
return new FieldValidation
{
IsRequired = false,
DataType = "String",
Length = 0,
Min = 0,
Max = 255,
FieldValidationType =
_bancPaydatabase.FieldValidationTypes
.FirstOrDefault(o => o.FieldName == fieldName),
IsVisible = true,
Owner_Country = swedishOwnerCountry
};
}
Usage would be now like this:
FieldValidation swedishFieldValidation1 = CreateFieldValidation("InvoiceNumber");
FieldValidation swedishFieldValidation2 = CreateFieldValidation("InvoiceTypeId");
If owner country would need to change, too, you would also make it a parameter in the method.

Related

Why does: '18 is not a valid value for the property "System.Windows.Documents.TextElement.FontSize" on a setter.' get thrown when setting FontSize?

I want to create a "DataGrid" in "WPF" when a "Button" is pressed.
Everything went fine, until I wanted to change the "FontSize" of the "ColumnHeader".
My Code so far:
var list = new ObservableCollection<TestClassForDataGrid>
{
new() { id = 1, name = "Herbert", bday = DateTime.Now },
new() { id = 2, name = "Harald", bday = DateTime.Now }
};
var fontSizeSetter = new Setter(Control.FontSizeProperty, 18);
var columnHeaderStyle = new Style(typeof(DataGridColumnHeader))
{
Setters = { fontSizeSetter }
};
var dataGrid = new DataGrid
{
ItemsSource = list,
AutoGenerateColumns = false,
ColumnHeaderStyle = columnHeaderStyle
};
dataGrid.Columns.Add(new DataGridTextColumn()
{ Binding = new Binding(path: "id"), Header = "ID", FontSize = 18 });
dataGrid.Columns.Add(new DataGridTextColumn()
{ Binding = new Binding(path: "name"), Header = "Name", FontSize = 18 });
dataGrid.Columns.Add(new DataGridTextColumn()
{ Binding = new Binding(path: "bday"), Header = "Birthday", FontSize = 18 });
Grid.SetColumn(dataGrid, 1);
Grid.SetRow(dataGrid, 1);
Grid.SetColumnSpan(dataGrid, 3);
Grid.SetRowSpan(dataGrid, int.MaxValue);
GridContent.Children.Add(dataGrid);
That is the Code inside my "OnClick" method.
Whenever I try to call this Method, I get an "Exception" saying, the Value 18 is not a valid property for "FontSize".
I also tried to set it as a string, but that gave mt the same error.
The "FontSize" in the "DataGridTextcolumn" works fine.
Why do I get this error?
I found the solution to this exception and it was a quite simple solution.
"FontSize" takes a double as it's parameter and C# sees 18 as an "int32".
For unknown reasons is it not possible for the constructor of the "Setter" class to implicitly convert the integer to double and throws this exception.
Just adding ".0" is enough to fix everything.
var fontSizeSetter = new Setter(Control.FontSizeProperty, 18.0);
The "Setter" class seems to be very picky with the datatype it gets and if it is not correct it freaks out.
Hopefully this will help someone in the future.

How to set default values for a query param with array type in .Net.Core with Swashbuckle by code

I am currently working with .NET Core 3.1 and Swashbuckle library. I have made several endpoints with requests decorated with attributes and proper swagger descriptions (I want to continue doing it this way).
Now I have a problem with the query parameter whose type is Array.
It is no problem to show this property with items to add.
enter image description here
I wish to fulfill them with default 12 values. It could be 12 x 0.
Something like:
[DefaultValue(new int[12] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })]
Also, I set [MaxLength(12)], but it also does not work.
I see for now even validation for numbers does not work.
For now, it looks like this:
/// <summary>
/// MyArray with 12x0 values.
/// </summary>
[DefaultValue(new int[12] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })]
[MaxLength(12)]
[Range(0, 1)]
public int[] MyArray { get; set; }
What do I want to achieve?
default values for 12 items with 0.
no less and no more than 12 items.
validation is in range 0,1
Thank you in advance!
Edit:
I have also tried custom AttributeFilter, but it changes nothing on swagger UI...
public class QueryArrayParameterFilter : IParameterFilter
{
public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
{
if (!parameter.In.HasValue || parameter.In.Value != ParameterLocation.Query)
return;
if (parameter.Schema?.Type == "array" && parameter.Name.Equals("MyArray"))
{
var value = null as IOpenApiExtension;
parameter.Extensions.TryGetValue("explode", out value);
if (value == null)
{
parameter.Extensions.Add("explode", new OpenApiBoolean(false));
}
parameter.Schema = new OpenApiSchema
{
Type = "array",
Items = new OpenApiSchema()
{
MaxItems = 2,
Type = "integer",
Format = "int64",
Example = new OpenApiArray()
{
new OpenApiInteger(0),
new OpenApiInteger(0)
},
Default = new OpenApiArray()
{
new OpenApiInteger(0),
new OpenApiInteger(0)
}
},
MaxItems = 3
};
}
}
}

How to pass a Method with parameters to another method

I'm trying to build up a Data Matrix which comprises a list of objects. So here's what I am trying to do:
List<IBasePremium> BasePremiumMatrix = new List<IBasePremium>();
List<ICalcRate> calcRates = new List<ICalcRate>
{
new CalcRate { BasePremiumType = 1, Rate = basePremiumRate.Building, Calc = basePremiumRate.Building },
new CalcRate { BasePremiumType = 2, Rate = basePremiumProduct.Building,Calc = calculator.BasePremium(basePremiumProduct.Building,basePremiumRate.Building) }
// new CalcRate { BasePremiumType = 3, Rate = (decimal)postcodeMultiplier.BuildingsCore ,Calc = calculator.BasePremium(postcodeMultiplier.BuildingsCore, ) },
};
on my line of code that is commented out, as the second parameter I really want to pass the value of 'Calc' from the previous line of code. I've got a number of lines like this where I need to pass the previous 'Calc' value to build the matrix. The above is clearly the wrong approach and thought that I'd be able to write a method that takes the form something like :
public CalcRate Multiplier(Func<string,decimal>, int basePremiumType, decimal rate) {.....}
But I'm fighting witrh passing the method name and it's parameter values.
Create and Action or a Func :
Action customAction = ()=> yourFunctionName(param1, param2);
then pass it to the multiplier.
var calcul = Multiplier(customAction , ....);
How about a for loop?
List<IBasePremium> BasePremiumMatrix = new List<IBasePremium>();
List<ICalcRate> calcRates = new List<ICalcRate>();
for (int i = 1; i < max; i++) {
CalcRate rate = new CalcRate { BasePremiumType = i , Rate = basePremiumRate.Building };
if ( i > 1) {
rate.Calc = calcRates.get(i - 2)
} else {
rate.Calc = calculator.BasePremium(basePremiumProduct.Building,basePremiumRate.Building);
}
calcRates.add(rate);
}

Comparing a single array against multiple different arays

For a small project on processor affinity, I want to create a simpler method than just a bunch of if(lvProcessors.Items[0].Checked == true && lvProcessors.Items[1] == true etc) comparing their exact values to see which code needs to be transferred to an (IntPtr).
To make the code slightly more efficiƫnt, I would like to compare an array containing booleans, to at least 14 other arrays containing booleans.
Example code:
var CheckState = new[] { lvProcessors.Items[0].Checked, lvProcessors.Items[1].Checked, lvProcessors.Items[2].Checked, lvProcessors.Items[3].Checked };
//setcore1 == 1, setcore2 == 2, etc
var SetCore1 = new[] { true, false,false,false };
var SetCore2 = new[] { true, true, false, false };
var SetCore3 = new[] { false, true, false, false };
var SetCore4 = new[] { true, false, true, false };
var SetCore5 = new[] { false, true, true, false };
var SetCore6 = new[] { true, true, true, false };
var SetCore7 = new[] { false, false, false, true };
var SetCore8 = new[] { true, false, false, true };
var SetCore9 = new[] { false, true, false, true };
var SetCore10 = new[] { true, true, false, true };
var SetCore11 = new[] { false, false, true, true };
var SetCore12 = new[] { true, false, true, true };
var SetCore13 = new[] { false, true, true, true };
var SetCore14 = new[] { true, true, true, true };
int switchcounter = 1;
switch (switchcounter)
{
case 15:
break;
default:
if (Enumerable.SequenceEqual(CheckState,<insertdynamicarrayname))
{
AffinityState = (IntPtr)switchcounter;
}
else
{
switchcounter++;
goto default;
}
break;
}
So if the first checkbox in the listview lvProcessors is checked, the var CheckState will generate an array containing { true, false,false,false }
This in turn must be compared to one of the SetCore arrays, and will in this case cause a match with SetCore1.
So what I would like to know is; how can I create a dynamic arrayname, based on the switchcounter on the code, that will fuse "SetCore" and switchcounter.ToString(), thus creating SetCore1, SetCore2, SetCore3, etc.
[EDIT]
As suggested by #Luaan, I've implemented his code to what I would've like it to be:
var SetCore1 = new[] { true, false, false, false};
[..]
var SetCore15 = new[] { true, true, true, true };
var allSets = new [] { SetCore1, SetCore2, SetCore3,SetCore4,SetCore5,SetCore6,SetCore7,SetCore8,SetCore9,SetCore10,SetCore11,SetCore12,SetCore13,SetCore14,SetCore15 };
foreach (var set in allSets)
{
MessageBox.Show(counter.ToString());
if (Enumerable.SequenceEqual(set, CheckState))
{
AffinityState = (IntPtr)counter;
break;
}
else if (Enumerable.SequenceEqual(set, CheckState) == false)
{
counter++;
}
}
EditProcess.ProcessorAffinity = (IntPtr)AffinityState;
In this code, depending on the input of the listviewcheckboxes, it will match the depending result to a SetCore and using the counter it will give the proper int which is converted at the end of the foreach loop and set the very specific cores(i.e. 1, 2 or 0, 2, 3, etc) to be used for the selected process which has been selected earlier in the code(not visible).
Thanks for the suggestion on bitmasks, they look useful, but currently I have no idea how to implement them without taking half my application apart.
Just make an array of arrays:
var allSets = new [][] { SetCore1, SetCore2, SetCore3, ... }
Then you can use a simple for cycle:
for (var i = 0; i < allSets.Length; i++)
HandleSet(allSets[i]);
Using Enumerable.SequenceEqual is going to be a bit slow. If you care about performance (I don't think you necessarily do in a case like this), have a look at BitArray - it's much smaller in memory, and the match is mostly a simple bitmasking.
EDIT:
If you want to convert between a bool[] and int (or byte, whatever you need), you can use something like this:
public bool[] ToBoolArray(int val)
{
var bits = new bool[sizeof(int) * 8];
for (var i = 0; i < bits.Length; i++)
{
bits[i] = (val & (1 << i)) > 0;
}
return bits;
}
public int ToInt32(bool[] bits)
{
var output = default(int);
for (var i = 0; i < bits.Length; i++)
{
output |= bits[i] ? 1 << i : 0;
}
return output;
}
This avoids having to deal with tons of annoying strings. Using a BitArray this is even simpler - creating a BitArray from int is trivial (there's a constructor), and changing it back to int can be done easily as above, just use bits.Get(i) instead of bits[i].
Or even better, make your own class for handling this:
public sealed class CpuMask
{
private int _bits;
public bool this[int index]
{
get { return (_bits & (1 << index)) > 0; }
set { if (value) _bits |= (1 << index); else _bits &= ~(1 << index); }
}
public CpuMask(int mask)
{
_bits = mask;
}
public CpuMask(IntPtr mask) : this(mask.ToInt32()) { }
public IntPtr ToIntPtr() { return new IntPtr(_bits); }
}

Render enumeration value using code blocks

I want the value of jsonStr to be
"{submitOfferResult: 0}"
instead though it is
"{submitOfferResult: OFFER_ACCEPTED}"
//javascript
var jsonStr = "{submitOfferResult: <%=SUBMIT_OFFER_RESULT.OFFER_ACCEPTED %>}";
//c#
public enum SUBMIT_OFFER_RESULT
{
OFFER_ACCEPTED = 0,
QUALIFYING_OFFER_NOT_MET = 1,
OFFER_ACCEPTED_NOT_HIGHEST_OFFER = 2,
OSP_CLOSED = 3,
AUTO_REJECTED = 4
}
Just cast to int:
var jsonStr = "{submitOfferResult: <%=(int) SUBMIT_OFFER_RESULT.OFFER_ACCEPTED %>}";
Otherwise it's calling ToString() on the enum value, which will use the name where possible.
Note that to follow .NET naming conventions, your enum would be:
public enum SubmitOfferResult
{
OfferAccepted = 0,
QualifyingOfferNotMet = 1,
OfferAcceptedNotHighestOffer = 2,
OspClosed = 3,
AutoRejected = 4
}
And then:
var jsonStr = "{submitOfferResult: <%=(int) SubmitOfferResult.OfferAccepted %>}";
You need to cast the enum to a numeric type:
(int)SUBMIT_OFFER_RESULT.OFFER_ACCEPTED

Categories