Mostafa Mostafa - 3 months ago 12
C# Question

A Method with 2 Kind of Return Type

Ok, I have 3 classes: Teacher, Student and Database for that matter. I wanna read data from database and put it in Teacher or Student. So i have to write something like this:

public Teacher dbSelect(string Table="Teacher")
{
Table = char.ToUpper(Table[0]) + Table.Substring(1);
string query = "SELECT * FROM " + Table + ";";
return dbConnect(query, true);
}


But i must have this exact Method with Student return:

public Student dbSelect(string Table="Student")
{
Table = char.ToUpper(Table[0]) + Table.Substring(1);
string query = "SELECT * FROM " + Table + ";";
return dbConnect(query, true);
}


Now I can write each one in their ViewModel, But I want to put them in Database class. So is there any way to do that?

(I know i can return them in a list and then work with that list, But just wanna know if there is a way or not!)

UPDATE:
I forgot to put dbConnect in here, so:

public List<Teacher> dbConnect(string query)
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
Teacher result = new Teacher(null, null, null, null, null, null, null, null);
// try
{
conn = new SQLiteConnection(db.db);
conn.Open();
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
}
// catch (Exception ex) { }
while (reader.Read())
{
Teacher temp = new Teacher(
reader[0].ToString(),
reader[1].ToString(),
reader[2].ToString(),
reader[3].ToString(),
reader[4].ToString(),
reader[5].ToString(),
reader[6].ToString(),
reader[7].ToString()
);
result.Items.Add(temp);
}
conn.Close();
return result.Items;
}


And again the exact thing exist for Student but returning:

public List<Student> dbConnect(string query)
{
...
}


Answer: I had a Base class and of course wanted to return a List with a specific type, So I used @Jauch answer, but with returning the List.

Answer

Here is an idea on how to do what you want, adapted from a code of mine:

public class BaseClass<T> 
    where T : new ()
{
    protected List<object> list;
    protected string query;
    protected PropertyInfo[] fProperties;
    protected Assembly fStoreAssembly;

    public BaseClass()
    {
        list = new List<T>();
        fStoreAssembly = Assembly.GetAssembly (typeof(T));
        fProperties = typeof(T).GetProperties();
    }

    public void Read()
    {
        SQLiteConnection conn = null;
        SQLiteCommand command = null;
        SQLiteDataReader reader = null;

        try
        {
            conn = new SQLiteConnection(db.db);
            conn.Open();
            command = new SQLiteCommand(query, conn);
            reader = command.ExecuteReader();

            StoreResults (reader);

            conn.Close();
        }
        catch (Exception ex) 
        {
            //deal with the exception here
        }
    }

    //Store results walks through all the records returned and 
    //creates new instances of the store object and saves in the list,
    //using reflection
    protected void StoreResults (SQLiteDataReader reader)
    {
        if (fProperties == null)
            throw new Exception ("Store type definition is missing");

        while (reader.Read ())
        {                
            object newStoreItem = fStoreAssembly.CreateInstance (typeof(T).FullName);                
            foreach (PropertyInfo pi in fProperties)
            {
                string lcName = pi.Name.ToLower ();

                if (HasColumn(reader, lcName))
                {
                    if (!reader.IsDBNull(reader.GetOrdinal(lcName)))
                        pi.SetValue(newStoreItem, reader[lcName], null);                    
                }
            }

            list.Add (newStoreItem);
        }
    }

    public bool HasColumn (SQLiteDataReader reader, string columnName)
    {
        foreach (DataRow row in reader.GetSchemaTable().Rows)
        {
            if (row ["ColumnName"].ToString () == columnName)
                return true;
        }
        return false;
    }
}

And here how you would create Teacher and Student

public class TeacherInfo
{
    //Properties for store info from database
}

public class Teacher : BaseClass<TeacherInfo>
{
     public Teacher ()
         : BaseClass()
     {
         query = "whatever you want here"
     }             
}

public class StudentInfo
{
    //Properties for store info from database
}

public class Student : BaseClass<StudentInfo>
{
     public Student ()
         : BaseClass()
     {
         query = "whatever you want here";
     }

}

As the Read routine is public, you can call Read from any instance of Teacher or Student. You can even create them and store as BaseClass and use it directly if you don't need to know if it is a student or a teacher (for common routines, etc)

This is not an extensive example, but just a point in the direction you could use to turn your code more generic.