How can I make code with out duplication of lines here?

Viewed 86
 Public Class ClassThree
   {
       ClassOne obj = null; //ClassOne:ClassThree
        ClassTwo obj2 = null; //ClassTwo:ClassThree
        public List<Query> GetQueries(string source)
        {
            List<Query> Queries = new List<Query>();
            if (source.Equals("ABCD"))
            {
                 obj = new ClassOne();
                AddQuerie(Queries, obj.GetQuery1());
                AddQuerie(Queries, obj.GetQuery2());
                AddQuerie(Queries, obj.GetQuery3());
                AddQuerie(Queries, obj.GetQuery4());
                AddQuerie(Queries, obj.GetQuery5());
                AddQuerie(Queries, obj.GetQuery6());             
            }
            else
            {
                obj2 = new ClassTwo();
                AddQuerie(Queries, obj2.GetQuery1());
                AddQuerie(Queries, obj2.GetQuery2());
                AddQuerie(Queries, obj2.GetQuery3());
                AddQuerie(Queries, obj2.GetQuery4());
                AddQuerie(Queries, obj2.GetQuery5());
                AddQuerie(Queries, obj2.GetQuery6());               
            }                
            return Queries;
        }
   } 

How to remove duplication of AddQuerie method. Is there any chance of writing single method but it must access the respective object of ClassOne or ClassTwo ?

NOTE: ClassOne GetQueryX() is different from ClassTwo GetQueryX()

Methods are totally different from one class to another

4 Answers

Method 1: Use an Interface

public interface IMultiQueryable
{
    string GetQuery1();
    string GetQuery2();
    string GetQuery3();
    string GetQuery4();
    string GetQuery5();
    string GetQuery6();
}

public class ClassOne : IMultiQueryable
{
    public string GetQuery1() => "";
    public string GetQuery2() => "";
    public string GetQuery3() => "";
    public string GetQuery4() => "";
    public string GetQuery5() => "";
    public string GetQuery6() => "";
}

public class ClassTwo : IMultiQueryable
{
    public string GetQuery1() => "";
    public string GetQuery2() => "";
    public string GetQuery3() => "";
    public string GetQuery4() => "";
    public string GetQuery5() => "";
    public string GetQuery6() => "";
}

Usage

public class ClassThree
{
    IMultiQueryable obj = null; 
    public List<Query> GetQueries(string source)
    {
        List<Query> Queries = new List<Query>();
        if (source.Equals("ABCD"))
        {
            obj = new ClassOne();          
        }
        else
        {
            obj = new ClassTwo();             
        }   
        
        AddQuerie(Queries, obj.GetQuery1());
        AddQuerie(Queries, obj.GetQuery2());
        AddQuerie(Queries, obj.GetQuery3());
        AddQuerie(Queries, obj.GetQuery4());
        AddQuerie(Queries, obj.GetQuery5());
        AddQuerie(Queries, obj.GetQuery6());               
        return Queries;
    }
}

Method 2: Use dynamic

public class ClassThree
{
    public List<Query> GetQueries(string source)
    {
        List<Query> Queries = new List<Query>();
        dynamic obj = null;
        if (source.Equals("ABCD"))
        {
            obj = new ClassOne();            
        }
        else
        {
            obj = new ClassTwo();            
        }     
            
        AddQuerie(Queries, obj.GetQuery1());
        AddQuerie(Queries, obj.GetQuery2());
        AddQuerie(Queries, obj.GetQuery3());
        AddQuerie(Queries, obj.GetQuery4());
        AddQuerie(Queries, obj.GetQuery5());
        AddQuerie(Queries, obj.GetQuery6());            
        return Queries;
    }
} 

You can put your GetQueryX() methods inside a list using add method (this code would have inevitably a repetitive structure) and then use a foreach loop where you AddQuerie() each entry in that list. This leaves you with only 1 call to AddQuerie() for each ClassOne and ClassTwo

There are a number of ways you could achieve this, but I can't help but wonder if the question you're asking is due to a design decision earlier that leads you to this question.

Also, you have a comment ClassOne obj = null; //ClassOne:ClassThree which leads me to believe that ClassOne and ClassTwo inherit from ClassThree? It may help if you go into a bit more detail of what you're trying to accomplish, aside from eliminating the duplication.

If ClassOne and ClassTwo do inherit from ClassThree, then you can avoid the string switching completely.

public List<Query> GetQueries(string source)
{
    List<Query> Queries = new List<Query>();
    if (source.Equals("ABCD"))
    {
        obj = new ClassOne();
        AddQuerie(Queries, GetQuery1());
        AddQuerie(Queries, GetQuery2());
        AddQuerie(Queries, GetQuery3());
        AddQuerie(Queries, GetQuery4());
        AddQuerie(Queries, GetQuery5());
        AddQuerie(Queries, GetQuery6());
    }
    return Queries;
}

Beyond that though, it would seem that internally the queries should simply be in a list, where you can get them without needing to one at a time.


    public interface ClassThree
    {
        List<Query> GetQueries();
    }

    public class ClassOne
    {
        private List<Query> queries;

        public List<Query> Queries
        {
            get => queries;
            private set => queries = value;
        }

        //...ways to populate the query list

        //You could even retain the named functions if needed
        public Query GetQuery1()
        {
            return queries[0];
        }
    }

Or take it one step further and use a factory class to create your Query container class, and skip the inheritence altogether.

NOTE: ClassOne GetQueryX() is different from ClassTwo GetQueryX()

Methods are totally different from one class to another

It would be expected in an inherited class that the method bodies are different. They must all have the same signature though. Do you also mean their names are different?

More details would help give a better solution.

The best way to address this issue is to make both classes implement an IGetQuery interface, as others have pointed out.

However, if you are unable to do that an alternative approach is to use reflection to call the methods you want.

Assuming that all your AddQuerie() method does is to add a Query to a List<Query> you can write your GetQueries() method like so:

public List<Query> GetQueries(string source)
{
    Query GetQuery(object obj, int n)
    {
        var method = obj.GetType().GetMethod("GetQuery" + n);
        return (Query)method.Invoke(obj, null);
    }

    if (source.Equals("ABCD"))
    {
        obj = new ClassOne();
        return Enumerable.Range(1, 6).Select(n => GetQuery(obj, n)).ToList();
    }
    else
    {
        obj2 = new ClassTwo();
        return Enumerable.Range(1, 6).Select(n => GetQuery(obj2, n)).ToList();
    }
}
Related