Search code examples
c#readability

How can I avoid repetitive code using reference types?


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.


Solution

  • 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;
    }