How to remove this duplicate code - c#

I have this same code on two places:
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
x = amount[0].Trim();
y = amount[1].Trim();
}
else
{
x = "1";
y = amountUnit.Trim();
}
//
unit = textInBrackets.Replace(amountUnit, "");
name = "";
for (int z = 0; z < i; z++)
{
name += someArray[z];
name += " ";
}
name = name.Trim();
The exact code is repeated twice. How to fix it? If i extract it in a new method, I'll have a lot of ref input parameters. Is there another way?
If it's not possible, just the part untill the comments?

Like:
public struct Parameters
{
public int X {get; set;}
public int Y {get; set;}
}
public Parameters ExtractParameters(string amountUnit)
{
var parameters = new Parameters();
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
parameters.X = int.Parse(amount[0].Trim());
parameters.Y = int.Parse(amount[1].Trim());
}
else
{
parameters.X = 1;
parameters.Y = int.Parse(amountUnit.Trim());
}
return parameters;
}
Usage:
var parameters = ExtractParameters(amountUnit);
var x = parameters.X;
var y = parameters.Y;
You can also make it an extension method on string.
And of course you best add some exception handling too.

The code seems to have two, separate blocks, logically.
One that deals with x and y - the other with name. These should probably be separate methods.
Now, you can create a type (class or structure) that encapsulates x and y, meaning that you only need to pass in one parameter. Instead of passing it by ref you can simply return it and in the caller replace what you passed in.

Combine your code and your data into a class ;-)
public class Point
{
public Point(string amountUnit)
{
if (amountUnit == null)
{
throw new ArgumentNullException("amountUnit");
}
if (amountUnit.ToLower().Contains("x"))
{
string[] amount = amountUnit.Split('x');
this.X = amount[0].Trim();
this.Y = amount[1].Trim();
}
else
{
this.X = "1";
this.Y = amountUnit.Trim();
}
}
string X { get; private set; }
string Y { get; private set; }
}

If you don't need anything very dynamic, how about splitting it into two methods, and doing something as simple as this:
public static string GetX(string amountUnit)
{
return amountUnit.ToLower().Contains("x") ?
amountUnit.Split('x')[0].Trim() :
"1";
}
public static string GetY(string amountUnit)
{
return amountUnit.ToLower().Contains("x") ?
amountUnit.Split('x')[1].Trim() :
amountUnit.Trim();
}

Related

Some parts I don't understand

C# code:
using System;
// this is the delegate declaration
public delegate int Comparer(object obj1, object obj2);
public class Name
{
public string FirstName = null;
public string LastName = null;
public Name(string first, string last)
{
FirstName = first;
LastName = last;
}
// this is the delegate method handler
public static int CompareFirstNames(object name1, object name2)
{
string n1 = ((Name)name1).FirstName;
string n2 = ((Name)name2).FirstName;
if (String.Compare(n1, n2) > 0)
{
return 1;
}
else if (String.Compare(n1, n2) < 0)
{
return -1;
}
else
{
return 0;
}
}
public override string ToString()
{
return FirstName + " " + LastName;
}
}
class SimpleDelegate
{
Name[] names = new Name[5];
public SimpleDelegate()
{
names[0] = new Name("Joe", "Mayo");
names[1] = new Name("John", "Hancock");
names[2] = new Name("Jane", "Doe");
names[3] = new Name("John", "Doe");
names[4] = new Name("Jack", "Smith");
}
static void Main(string[] args)
{
SimpleDelegate sd = new SimpleDelegate();
// this is the delegate instantiation
Comparer cmp = new Comparer(Name.CompareFirstNames);
Console.WriteLine("\nBefore Sort: \n");
sd.PrintNames();
// observe the delegate argument
sd.Sort(cmp);
Console.WriteLine("\nAfter Sort: \n");
sd.PrintNames();
}
// observe the delegate parameter
public void Sort(Comparer compare)
{
object temp;
for (int i=0; i < names.Length; i++)
{
for (int j=i; j < names.Length; j++)
{
// using delegate "compare" just like
// a normal method
if ( compare(names[i], names[j]) > 0 )
{
temp = names[i];
names[i] = names[j];
names[j] = (Name)temp;
}
}
}
}
public void PrintNames()
{
Console.WriteLine("Names: \n");
foreach (Name name in names)
{
Console.WriteLine(name.ToString());
}
}
}
There are two parts of the code that I don't understand at all. What do these parts exactly do, (respectively); and what subject(s) do I need to learn to understand these parts?
string n1 = ((Name)name1).FirstName;
What does ((Name)name1) do?
public void Sort(Comparer compare)
Can anyone provide any tips or feedback on how those parts of the code function? Can you possibly lead me into the right direction?
First: string n1 = ((Name)name1).FirstName
(Name)name1 which can be written generically as (Type)variable. What this does is take the variable and attempt to cast (a synonym would be convert) the variable name1 into the type Name. This then allows us to access the FirstName property.
Learn more here: https://www.w3schools.com/cs/cs_type_casting.asp
Second: public void Sort(Comparer compare)
This is a method declaration.
public indicates the accessibility. Other options include private, protected and a few others. public indicates that this method can be called by any code that has a reference to an instance of this object.
void indicates the return type. void is a special keyword to mean that no value is returned from the method.
Sort is the method name
Compare compare: Compare is the type of the parameter to be passed in and compare is the name of the parameter which can be used throughout the method.
Learn more here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods

Search a 2 dimensional list for a string in another list

I want to check if a value in one list is in a second list. The second list is a 2 dimensional list defined in a class.
Here's some sample data.
tagNoMatchList[0] = "</Configuration>"
tagNoMatchList[1] = "<SWCheck>"
tagNoMatchList[2] = "</SWCheck>"
tagNoMatchList2[0].col = "A29"
tagNoMatchList2[0].tag = "</Configuration>"
tagNoMatchList2[1].col = "A52"
tagNoMatchList2[1].tag = "</SWCheck>"
public class tagNoMatchClass
{
public string tag { get; set; }
public string col { get; set; }
}
var tagNoMatchList = new List<string>();
var tagNoMatchList2 = new List<tagNoMatchClass>();
tagNoMatchList2.Add(new tagNoMatchClass
{
tag = formatTag,
col = Globals.ConvertColumnNumberToName(Globals.HeaderColumns[Globals.COLUMN_FORMATTING_TAG]) + rowIdx.ToString(),
});
bool test = tagNoMatchList[formatTagError].Any(x => tagNoMatchList2.Any(y=>x.Equals(y.tag)));
In the code above, test always has a value of false. It should be true when it tests tagNoMatchList[0] == tagNoMatchList2[0].tag and tagNoMatchList[2] == tagNoMatchList2[1].tag
I have tried various things and can't figure out what I'm doing wrong.
Thank you, jdweng. I must have my terminology wrong. I referred to tagNoMatchClass as a 2 dimensional List. It almost works, but not quite. The code below gives me exactly the opposite of what I want.
for (int formatTagError = 0; formatTagError < tagNoMatchList.Count; formatTagError++)
{
if (tagNoMatchList2.Any(x => x.tag == tagNoMatchList[formatTagError]))
{
// Do something
}
}
I tried the following, but the if always evaluates to true. There's something that I'm not understanding about the Any syntax.
for (int formatTagError = 0; formatTagError < tagNoMatchList.Count; formatTagError++)
{
if (tagNoMatchList2.Any(x => x.tag != tagNoMatchList[formatTagError]))
{
// Do something
}
}
Try something like this :
public class tagNoMatchClass
{
public string tag { get; set; }
public string col { get; set; }
}
public class Test
{
List<string> tagNoMatchList = new List<string>();
List<tagNoMatchClass> tagNoMatchList2;
public Test()
{
tagNoMatchList2 = new List<tagNoMatchClass>();
tagNoMatchList.Add("</Configuration>");
tagNoMatchList.Add("<SWCheck>");
tagNoMatchList.Add("</SWCheck>");
tagNoMatchList2.Add(new tagNoMatchClass() { col = "A29", tag = "</Configuration>"});
tagNoMatchList2.Add(new tagNoMatchClass() {col = "A52", tag = "</SWCheck>"});
bool test = tagNoMatchList2.Any(x => x.tag == tagNoMatchList[0]);
}
}
It works like this:
for (int formatTagError = 0; formatTagError < tagNoMatchList.Count; formatTagError++)
{
if (!tagNoMatchList2.Any(x => x.tag == tagNoMatchList[formatTagError]))
{
// Do something
}
}
Thanks very much for getting me close enough to where I could figure out the rest.

Json Deserialize object error

Ok, now I am running into a very weird error. I am trying to deserialize a GameEvent object which is like this:
public class GameEvent {
public Location eventLocation = Location.NoLocation;
public Location targetLocation = Location.NoLocation;
public string eventTriggerName = ""; // Who (Piece or tactic) triggers this event
public string targetTriggerName = ""; // Target name
public int eventPlayerID = -1;
public int targetPlayerID = -1;
public string result = ""; // Piece, Tactic, Trap, Freeze, Move, Kill, Flag
public int amount = 0;
public GameEvent() { Debug.Log("Fuck"); }
public static string ClassToJson(GameEvent gameEvent)
{
return JsonConvert.SerializeObject(gameEvent);
}
}
When I deserialize it by doing this, however, it is changed weirdly.
public static GameEvent JsonToClass(string json)
{
Debug.Log(json);
GameEvent gameEvent = JsonConvert.DeserializeObject<GameEvent>(json);
Debug.Log(ClassToJson(gameEvent));
return JsonConvert.DeserializeObject<GameEvent>(json);
}
As you can see from the picture below the eventLocation should be (7,2) but after deserialization it becomes (4,2). And the eventLocation is the only thing that's changed.
string json = "{\"eventLocation\": {\"x\": 7, \"y\": 2}, \"targetLocation\": {\"x\": 4, \"y\": 2} }";
var x = GameEvent.JsonToClass(json);
I have no clue why. This is my Location class
public class Location
{
public int x = -1;
public int y = -1;
public Location(){}
public Location(int X, int Y)
{
x = X;
y = Y;
}
public Location(Location location)
{
x = location.x;
y = location.y;
}
public static bool operator !=(Location a, Location b)
{
UnityEngine.Debug.Log(a + " " + b);
return a.x != b.x || a.y != b.y;
}
public static Location NoLocation = new Location(-1, -1);
}
I didn't post all the functions of GameEvent and Location class but I posted all the variables they have.
By the way I also met another weird problem with the Location. When I do if(eventLocation != Location.NoLocation), the != operator that I override is actually not comparing eventLocation with Location.NoLocation but eventLocation(yeah itself). So the a and b will always be the same and != will always return me false. I also have no clue why.
Thanks in advance!!!
Your problem comes from these two line:
public Location eventLocation = Location.NoLocation;
public Location targetLocation = Location.NoLocation;
It is happening because you are binding both objects to an specific object which is NoLocation. It means both of the eventLocation and targetLocation are pointing to the same object in the heap memory and changing one of them changes the other one as well.
Changing NoLocation to something like this can solve your issue:
public static Location NoLocation { get { return new Location(-1, -1); } }

Using enum item to call a method

I have an enum with 30 items in it. Each item has a corresponding function with the same name. I would like to be able to call the function by referencing the enum at a certain position.
So if the value at enum[0] = Foo, I would like to be able to call Foo(string bar) by using something like enum(0)("foobar")
In the end the point is I am running each function as a task like so:
enum Test { AA, BB, CC, DD ....}
tasks[0] = Task.Run(() => { prices[0] = AA("a string"); });
tasks[1] = Task.Run(() => { prices[1] = BB("a string"); });
tasks[2] = Task.Run(() => { prices[2] = CC("a string"); });
//for 30 tasks
What I would like to do is something along the lines of:
enum Test { AA, BB, CC, DD ....}
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() => { prices[i] = (Test)i("a string"); });
}
Task.WaitAll(tasks.ToArray());
Is this something that is even possible?
EDIT:
The enum relates to controls on a form so i have an array of textboxs, label and a array of prices that is populated with the results of the functions:
enum Dealers { Dealer1, Dealer2 ... Dealer29, Dealer30 };
static int noOfDealers = Enum.GetNames(typeof(Dealers)).Length;
decimal[] prices = new decimal[noOfDealers];
TextBox[] textBox = new TextBox[noOfDealers];
Label[] boxes = new Label[noOfDealers];
for (int i = 0; i < noOfDealers; i++)
{
textBox[i] = Controls.Find("txt" + (Dealers)i, true)[0] as TextBox;
boxes[i] = Controls.Find("box" + (Dealers)i, true)[0] as Label;
prices[i] = 0;
}
//RUN 30 TASKS TO POPULATE THE PRICES ARRAY
for (int i = 0; i < noOfDealers; i++)
{
textBox[i].Text = "£" + prices[i].ToString();
}
//LOOP THROUGH PRICES ARRAY AND FIND CHEAPEST PRICE, THEN COLOUR THE LABEL BACKGROUND GREEN FOR THE TEXT BOX WITH THE NAME AT ENUM VALUE WHATEVER I IS
I guess i am just trying to make my code as concise as possible, there is the potential for the amount of tasks to double and didn't want to end up with 60 lines to populate the tasks array
I would create dictionary and map enum to actions:
Dictionary<Test, Func<string,double>> actions = new Dictionary<Test, Func<string,double>>()
{
{Test.AA, (x) => { return 5;}},
{Test.BB, (x) => { return 15; }},
}; //x is your string
var res = actions[Test.AA]("hello");
I would strongly suggest using a built in construct - like an extension method and a simple switch:
public static int GetPriceWithString(this Test test, string str)
{
switch (test)
{
case Test.AA:
break;
case Test.BB:
break;
case Test.CC:
break;
case Test.DD:
break;
default:
throw new ArgumentOutOfRangeException(nameof(test), test, null);
}
}
then your loop looks almost the same:
for (int i = 0; i < 30; i++)
{
tasks[i] = Task.Run(() =>
{
prices[i] = ((Test)i).GetPriceWithString("a string");
});
}
What you want to do is possible with reflection, which can be a powerful tool - but ideally should only be used as a last resort, as it will hide what could be compile time errors, and cause less code readability.
Using a simple switch like this makes your code self-documented, so when you come back to this in a month you can quickly remember what the intention was.
How about using an array of delegates:
using System;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
private static int AA(string a) { return 0; }
private static int BB(string a) { return 1; }
private static int CC(string a) { return 2; }
private static Func<string, int>[] functions = new Func<string, int>[] { AA, BB, CC };
private static int[] prices = new int[functions.Length];
private static Task[] tasks = new Task[functions.Length];
static void Main(string[] args)
{
for (int i = 0; i < functions.Length; ++i)
tasks[i] = Task.Run(() => { prices[i] = functions[i]("a string"); });
Task.WaitAll(tasks);
}
}
}
An eg. speaks a lot more than words.
I used it in a winform so the this refers to win form.
I have assumed all your methods are public , have same signature & return the same type.
enum MyName { AA,BB,CC};
//Call this in one of your methods
string [] strVal= Enum.GetNames(typeof(MyName));
int x = CallFunction(strVal[0], "A");
int y = CallFunction(strVal[1], "h");
int z = CallFunction(strVal[1], "C");
//End Call this in one of your methods
int CallFunction(string strName,string strValue)
{
return Convert.ToInt32(this.GetType().InvokeMember(strName, BindingFlags.Public | BindingFlags.InvokeMethod|BindingFlags.Instance, null, this, new object[] { strValue }));
}
public int AA(string s)
{
return 1;
}
public int BB(string s)
{
return 2;
}
public int CC(string s)
{
return 3;
}
Another solution. I hope somebody will consider it as overkill :)
Create abstract class DealerBase.
public abstract class DealerBase
{
public string Name { get; }
public decimal Price { get; set; }
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
}
Then create classes for every dealers you have and implement own logic for UpdatePrice method.
public class Dealer1 : DealerBase
{
public Dealer1() : base("DealerOne") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerOneCalculationMethod();
}
}
public class Dealer2 : DealerBase
{
public Dealer2() : base("DealerTwo") { }
public override void UpdatePrice()
{
//Calculate price
Price = DealerTwoCalculationMethod();
}
}
And so on..
Then you just create collection of dealers which can be easily iterated
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
}
foreach(var dealer in dealers)
{
dealer.UpdatePrice();
}
You can loop dealers and generate textboxes, labels in the winforms.
But I suggest to use DataGridView where code will be tiny clearer.
First implement INotifyPropertyChanged interface in the base class DealerBase
public abstract class DealerBase : INotifyPropertyChanged
{
public string Name { get; }
protected decimal _Price;
public decimal Price
{
get { return _Price; }
set
{
if (Equals(_Price, value)) return;
_Price = value;
// next method will inform DataGridView about changes
// and update value there too
RaisePropertyChanged();
}
protected DealerBase(string name)
{
Name = name;
}
public abstract void UpdatePrice();
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
The in the Form you can create BindingList<DealerViewModelBase> and set it to DataGridView.DataSource
public class YourForm: Form
{
public YourForm()
{
InitializeComponent();
var dealers = new List<DealerBase>
{
new Dealer1(),
new Dealer2()
};
var bindSource = new BindingList<DealerBase>(dealers);
dataGridView.DataSource = bindSource;
}
// Add button which update prices for all dealers
private void ButtonUpdatePrices_Click(object sender, EventArgs e)
{
var dealers = (BindingList<DealerBase>)dataGridView.DataSource;
foreach (var dealer in dealers)
{
dealer.UpdatePrice();
// Because we call `RaisePropertyChanged` in
// setter of Price - prices will be automatically
// updated in DataGridView
}
}
}
Idea of this approach you put different logic of different dealers in the separated class which. Because all dealer classes will inherit from same abstract class you can add different dealers to the collection.
You already have hardcoded enums and correspondent method which you try to link together. This approach make using of dealers collection little bid easy

encapsulation of an array of objects c#

I would like to create an array of objects. Each object has it's own int array.
For each object I assign values to it's array ONLY with keys given by myself (example: li[i].V[10] = 1; li[i].V[50] = 10; )
Can someone tell me how to do that? Can I do that without using Lists?
The second case is analogical to first. I would like to know how to assign values of object's List
using setter.
I tried to do that by myself. Unfortunately My code crashed cuz I don't know how to set the dimension of V and Word:
class CFiles
{
//private int[] v=new int[5];//dont want to specify the dimention of array here
private int[] v;//vector of file
private List<string> words;
public CFiles()
{
words = Words;
v = new int[50];
v = V;
}
public int[] V { get; set; }
public List<string> Words { get; set; }
}
class Program
{
static void Main(string[] args)
{
CFiles[] li = new CFiles[2];
for(int i=0;i<li.Length;i++)
{
li[i]=new CFiles();
li[i].V[10] = 1;
li[i].V[50] = 10;
li[i].V[50] = 15;
li[i].Words.Add("a");
li[i].Words.Add("ab");
li[i].Words.Add("abc");
}
for (int i = 0; i < li.Length; i++)
{
for(int j=0;j<li[i].V.Length;j++)
{
Console.WriteLine(li[i].V[j]);
}
}
Console.WriteLine();
}
}
Your constructor isn't right and your properties aren't quite right. You might want something more like this:
class CFiles
{
//private int[] v=new int[5];//dont want to specify the dimention of array here
private int[] v;
public int[] V { get { return v; } set { v = value; } }
private List<string> words;
public List<string> Words { get { return words; } set { words = value; } }
public CFiles()
{
words = new List<string>();
v = new int[51]; //needs to be 51 if you are going to assign to index 50 below
}
}
Other than those issues, your code seems to do what you want. You have an array of objects where each object has its own int array (in addition to a string of strings).
Is that not what you want?

Categories

Resources