问题描述
我试图实现一个包装器,以使用System.Data.sqlite功能,以一种良好的OOP方式消除重复的代码。因此,我有以下通用方法:
public T SendSelectQuery<T>(string sql,Func<sqliteDataReader,T> processResult) where T : IDBResult
{
try
{
using (var dbConnection = new sqliteConnection("path"))
using (var cmd = new sqliteCommand(sql,dbConnection))
{
dbConnection.open();
cmd.CommandType = CommandType.Text;
using (sqliteDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
return processResult(rdr);
}
}
}
catch (Exception ex)
{
return T ??????
}
}
T是结果对象,即:
public interface IDBResult
{
bool Completed { get; set; }
string Exception { get; set; }
}
public abstract class CustomDBREsult : IDBResult
{
public bool Completed { get; set; }
public string Exception { get; set; }
public string Payload { get; set; }
public CustomDBREsult(bool Completed,string exception,string Payload)
{
this.Completed = Completed;
this.Exception = exception;
this.Payload = Payload;
}
}
public class SuccessCustomDBResult : CustomDBREsult
{
public SuccessCustomDBResult(string Payload) : base(true,string.Empty,Payload)
{
}
}
public class ErrorCustomDBResult : CustomDBREsult
{
public ErrorCustomDBResult() : base(false,"exception",string.Empty)
{
}
}
我想打电话给SendSelectQuery<CustomDBREsult>(...)
并获得一个CustomDBREsult
子实例。
您可能已经注意到问题发生在catch
段中,在该段中我需要返回一个T
对象,但是我无法实例化一个从CustomDBREsult
派生的approprite Error对象。
我可以将SendSelectQuery<T>
的返回类型更改为IDBResult
并在catch
段中返回,如下所示:
public class DefaultDBError : IDBResult
{
public bool Completed { get; set; } = false;
public string Exception { get; set; } = "db exception";
}
但是在这种情况下,我需要将SendSelectQuery<T>
的结果从IDBResult
强制转换为T
。而且这似乎不是一个很好的做法。
IDBResult res = DBMethods.SendSelectQuery<CustomDBREsult>("sql query",processResult);
if (res is CustomDBREsult cdbres)
{
}
else if (res is DefaultDBError ddberror)
{
}
另一种选择是“提起” try
catch
块并在其中使用SendSelectQuery<T>
,但是我需要在使用SendSelectQuery<T>
的任何地方复制此块,然后仍将IDBResult
转换为T
。
如果smn能够理解我,请感谢您的评论。我想我的问题是对逻辑进行了很好的抽象。
解决方法
我认为您在这里过度设计了问题。
首先,IDBResult接口实际上没有任何作用,因此您可以消除它。
让抽象类派生该类的成功和失败版本,它们自己似乎什么也没做,只是指出是失败还是成功,实际上并不能真正起到很多作用目的。
由于您要在原始Select中使用T作为有效负载,因此我会将您的自定义db结果更改为通用类型。
public class CustomDBREsult<T>
{
public bool Completed { get; set; }
public string Exception { get; set; }
public T Payload { get; set; }
public CustomDBREsult(bool Completed,string exception,T Payload)
{
this.Completed = Completed;
this.Exception = exception;
this.Payload = Payload;
}
}
尽管如此,除非这是您要挑战自己的一项练习,以提高您的设计技能,或类似的方法,否则那里有很多好的库已经为您完成了大部分工作,并且可以节省很多时间重新发明轮子。