I've made a method to split address line into separate distinct categories like Region, City, Street and House which are represented by a single class. It follows relatively simple structure.
Address useOther(string Casual, string Other)
{
Address
address = new Address();
List<string>
split = new List<string>();
char[]
separator = { ',' };
split.AddRange(
Casual.Split(
separator,
StringSplitOptions.RemoveEmptyEntries));
split.AddRange(
Other.Split(
separator,
StringSplitOptions.RemoveEmptyEntries));
// Initialize parameters
split = RemoveBannedTokens(split);
for (int i = 0; i < split.Count; i )
{
(address.Region, split[i]) = findRegionByName(split[i]);
if (address.Region != null)
{
split[i] = split[i].Replace(address.Region.Name, "");
break;
}
}
if (address.Region == null)
{
address.Region = new Region(region);
}
split = ClearSplit(split);
// Finding region
for (int i = 0; i < split.Count; i )
{
(address.City, split[i]) = findSityByName(split[i]);
if (address.City != null)
{
split[i] = split[i].Replace(address.City.Name, "");
break;
}
}
if (address.City == null)
{
for (int i = 0; i < split.Count; i )
{
(address.City, split[i]) = findCityByName(split[i], false);
if (address.City != null)
{
split[i] = split[i].Replace(address.City.Name, "");
break;
}
}
}
if (address.City == null)
return address;
split = ClearSplit(split);
// Finding city
for (int i = 0; i < split.Count; i )
{
(address.Street, split[i]) = findStreetByName(split[i], address.City);
if (address.Street != null)
{
split[i] = split[i].Replace(address.Street.Name, "");
break;
}
}
if (address.Street == null &&
(address.Region.Code.Replace("/", "")
address.City.Code.Replace("/", "")).Length != 13)
return address;
split = ClearSplit(split);
//Finding street
int
cityIndex = address.City.Index,
streetIndex = address.Street.Index;
for (int i = 0; i < split.Count; i )
{
split[i] = split[i].Replace("б/н", "");
}
address.House = findNumbers(split.ToArray(), cityIndex, streetIndex);
return address;
}
If you can see repetition goes like this
for (int i = 0; i < split.Count; i )
{
(address.Something, split[i]) = findSomethingByName(split[i]);
if (address.Something != null)
{
//do this thing
break;
}
}
if (address.Something == null)
//try other thing
split = ClearSplit(split);
I want to avoid this repetition and have something of an array or foreach loop but couldn't find a clear way of making an array with reference values or a foreach reference loop that would work with null values properly. I have thought about making a function with specified inputs and outputs but decide it would only harm ability to read my code, which I'm trying to improve here.
CodePudding user response:
Let me try to demonstrate your problem and my proposal.
Assumptions
- Your class has several similiar properties, all with value of
String
. - You have to keep the properties, because they may be required by other frameworks.
- You have repeative code to work with the properties.
OldAddress
public class OldAddress
{
public string City { get; set; }
public string Region { get; set; }
}
Old Program
public class Program
{
static OldAddress oldAddress;
public static string GetFromDataSource(string prop)
{
return null;//should return your real value
}
public static void AssignValueOldWay()
{
if (oldAddress.City != null)
{
oldAddress.City = GetFromDataSource("City");
}
if (oldAddress.Region != null)
{
oldAddress.Region = GetFromDataSource("Region");
}
// more...
}
}
NewAddress
public class NewAddress
{
public static string[] PropNames = { "City", "Region" };
public NewAddress()
{
props = new Dictionary<string, string>();
foreach (string prop in PropNames)
{
props.Add(prop, "");
}
}
public string City
{
get
{
return GetProperty("City");
}
set
{
SetProperty("City", value);
}
}
public string Region
{
get
{
return GetProperty("Region");
}
set
{
SetProperty("Region", value);
}
}
private Dictionary<string, string> props;
public void SetProperty(string prop, string value)
{
props[prop] = value;
}
public string GetProperty(string prop)
{
return props[prop];
}
}
New Program
public class Program
{
public static string GetFromDataSource(string prop)
{
return null;//should return your real value
}
static NewAddress newAddress;
public static void AssignValueNewWay()
{
foreach (string prop in NewAddress.PropNames)
{
if (newAddress.GetProperty(prop) != null)
{
newAddress.SetProperty(prop, GetFromDataSource(prop));
}
}
}
}
Note my code is just to demonstrate the idea, not optimized for runtime exceptions or bad styles such as public fields, or magic strings.
CodePudding user response:
After some thinking and looking on how I could manage this, I have decided to follow JAlex advise. For now I don't think this change is necessary, so I leave it be for now. What I will do is I would try make this more readable by using additional spaces and comments. As of for now my method looks something like this (after a bit of tweaking here and there) and I'm more or less happy with how readable it is
Address useOther(string Casual, string Other)
{
Address address =
new Address();
//Initialize address
List<string> split =
new List<string>();
char[] separator =
{
','
};
//Initialize split and separators
split.AddRange(Casual.Split(separator));
split.AddRange(Other .Split(separator));
RemoveBannedTokens(ref split);
//Fill split
for (int i = 0; i < split.Count; i )
{
(address.Region, split[i]) =
findRegionByName(split[i]);
if (address.Region != null)
break;
}
//Trying to find region
if (address.Region == null)
address.Region = new Region(region);
//If Region is not found
ClearSplit(ref split);
//Get rid of empty strings
for (int i = 0; i < split.Count; i )
{
(address.City, split[i]) =
findSityByName(split[i]);
if (address.City != null)
break;
}
//Trying to find city
if (address.City == null)
{
for (int i = 0; i < split.Count; i )
{
(address.City, split[i]) =
findSityByName(split[i], false);
if (address.City != null)
break;
}
}
//Trying to find city with additional params
if (address.City == null)
return address;
//If City is not found
ClearSplit(ref split);
//Get rid of empty strings
for (int i = 0; i < split.Count; i )
{
(address.Street, split[i]) =
findStreetByName(split[i], address.City);
if (address.Street != null)
break;
}
//Trying to find street
string code =
address.Region.Code.Replace("/", "")
address.City.Code .Replace("/", "");
//Initialize code
if (address.Street == null && code.Length != 13)
return address;
//If Street is not found and address is not complete
ClearSplit(ref split);
//Finding street
address.House = findNumbers(split);
//Trying to find house
return address;
}