【问题标题】:A Method with 2 Kind of Return Type具有 2 种返回类型的方法
【发布时间】:2016-08-21 14:16:34
【问题描述】:

好的,我有 3 个班级:TeacherStudentDatabase。我想从数据库中读取数据并将其放入 TeacherStudent。所以我必须写这样的东西:

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

但我必须有这个确切的方法,学生返回:

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

现在我可以在它们的 ViewModel 中编写每一个,但我想将它们放在 Database 类中。那么有没有办法做到这一点呢?
(我知道我可以将它们返回一个列表,然后使用该列表,但只是想知道是否有办法!)

更新: 我忘了把 dbConnect 放在这里,所以:

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

对于学生来说,同样的事情仍然存在,但返回:

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

回答:我有一个 Base 类,当然想返回一个具有特定类型的 List,所以我使用了 @Jauch 回答,但返回 List

【问题讨论】:

  • 嗨@Mostafa。一些想法。 1. 两个例程将返回完全相同的值,即 dbConnect 返回的值。 2、cbConnect返回的可能READER和Student/Teacher是什么关系?
  • 你好@Jauch。一名返校学生,一名返校教师。实际上,这就是我必须提出的问题! :D。我马上去修!
  • 啊...现在清楚多了:)
  • 我做了类似的事情,但是我使用了一个基于泛型和接口的系统。为了“填充”可以具有不同列/属性的对象(例如教师或学生),我使用反射将阅读器中的列与对象中的属性相匹配。
  • 如果你能给我一个例子,那就太好了。因为我不知道它们是如何工作的。非常感谢。

标签: c# wpf methods


【解决方案1】:

这是一个关于如何做你想做的事的想法,改编自我的代码:

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

在这里你将如何创建教师和学生

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

}

由于 Read 例程是公开的,因此您可以从 Teacher 或 Student 的任何实例调用 Read。 您甚至可以创建它们并将其存储为 BaseClass,如果您不需要知道它是学生还是老师(用于常见例程等),则可以直接使用它

这不是一个广泛的示例,而只是您可以用来使您的代码更通用的方向上的一点。

【讨论】:

  • 非常感谢!这对我来说是全新的:D,所以我现在必须努力。
  • @Mostafa,希望对您有所帮助。我建议你学习泛型、接口和反射:)
【解决方案2】:

您可以遵循使用接口的语义来返回值,然后将返回类型转换为适当的类型,或者使用基类(接口会更好,因为您仍然可以在实现界面)。实体接口可以如下创建,

public interface SchoolEntity { 
    // Provide the similar properties as members of this interface.
}

然后你可以在你的TeacherStudent中实现这个接口。

public class Student : SchoolEntity { }
public class Teacher : SchoolEntity { }

最后,使用枚举可以使参数更加清晰。它们在阅读时会更清晰,而不是具有相同的参数类型。 请注意,函数重载不会将返回类型视为签名差异

enum Entity { Teacher, Student }

然后您可以检查要返回的数据。

public SchoolEntity dbSelect(Entity type)
{
    switch(type) {
         case Teacher:
             var query = "SELECT * FROM Teacher";
             return dbConnect(query, true);
         // Rest of the cases.
    }
}

请注意,您的 SQL 语句对 SQL 注入开放,任何人都可以删除表,或执行可以传递给引擎的操作。

在列表中工作

使用列表不是一个好主意。毕竟,你会返回什么列表?那是public List&lt;Teacher&gt; dbSelect 还是public List&lt;Student&gt; dbSelect?这个问题的答案和解决方案是使用相同的类型来备份这两种类型。

dbSelect函数

请注意,您仍然只返回 Teacher 类型,那为什么还要有一个 Student 呢?你绝对应该把它扔回去。事实上,如果我必须开发这个。我必须使用dbSelect 函数将Entity 作为参数,以将所有数据库请求和处理保存在一个函数中。

public List<Teacher> dbConnect(Entity type)
{
    SQLiteConnection conn = null;
    SQLiteCommand command = null;
    SQLiteDataReader reader = null;
    Teacher result = null; // Can be set to null.
        //    try
        {
            conn = new SQLiteConnection(db.db);
            conn.Open();
            string query;

            // This way, leave the function to build the query.
            if(type == Entity.Teacher) {
                query = "SELECT * FROM Teacher";
            } else {
                query = "SELECT * FROM Student";
            }
            command = new SQLiteCommand(query, conn);
            reader = command.ExecuteReader();
        }
        //   catch (Exception ex) { }

        while (reader.Read())
        {
            if(type == Entity.Teacher) {
                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);
            } else {
                // Add the student.
            }
        }
    conn.Close();
    return result;
}

现在在这段代码中,您知道resultTeacher 类型。那里没有列表,这使您的代码有点混乱。接受我的建议:重新编写代码。

还请浏览以下有用的链接:

Explicit Interface Implementation
https://en.wikipedia.org/wiki/SQL_injection
Signatures and overloading

【讨论】:

  • 非常感谢!但是 Teacher 的 dbConnect 类型是 List&lt;Teacher&gt;Student 的 dbConnect 类型是 List&lt;Student&gt;。作为您的第一个解决方案,我无法理解 dbSelect 如何同时返回 List&lt;Teacher&gt;List&lt;Student&gt;。如果您能再解释一下,我将不胜感激。 注意:感谢您让我了解 SQL 注入。
  • @Mostafa,它不会。它将返回List&lt;SchoolEntity&gt;,您可以稍后将其转换为TeacherStudent。这就是必须实现接口或基类的用法。
  • 据我所知,我必须在 SchoolEntity 中声明成员属性(如您所说),但教师的属性与学生不同,例如一个有密码,另一个没有。那么我该如何使用它呢?
猜你喜欢
  • 2016-04-20
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 2013-04-16
  • 1970-01-01
相关资源
最近更新 更多