WinForm/C# PEMSoft 类库 DataSource 在设计时的一点建议

xinggang · 2017年07月28日 · 112 次阅读

我们的 PEMSoft 开发框架为了大家开发的效率做了大量优化工作,目前功能已经比较完善,但个人认为有些地址仍能继续优化继而进一步提高大家编程效率,此次的例子是通用类库的设计。
我们平时编程中用到最多的和服务器打交道的就是用DataSource进行数据交互,我们先分析一下现在平台为我们提供的DataSource使用方法。

Hashtable ht = new Hashtable();
ht["DataSetName"]="DSGetData";
ht["TableNames"] = "T02";
ht["{UserName}"] = AppInfo.UserName;
if (DataSource.GetDataSet(ht)["IsSuccess"].Equals("0")) { e.Cancel = true; return; }

DataTable dt = (DataSource.DataSets["DSGetParamInfo"] as DataSet).Tables[0];

//数据是否修改
if (result["IsChanged"].Equals("0")) { return true; }

//是否需要保存
if (isAskUpdate)
{
    if (result["IsUpdate"].Equals("-1")) { return false; } //-1是什么
    if (result["IsUpdate"].Equals("0")) { return true; } //0是什么
}

看过上面的代码大家一定感觉非常亲切,因为用久了,应该也不会有什么感觉了,老夫老妻之间似乎都没有激情~
那么问题来了,

  1. ht 里面的 DataSetName 每次要自己敲?还有 TableNames,先不说不小心敲错了,每次都敲一遍也很痛苦,当然你可以从别处复制。 然后除了这几个内置的名字还有其它的吗?答案是有,自己去查开发手册,记不起来了只能去查手册。
  2. GetDataSet() 方法返回了一个 Hashtable,天哪,这个 Hashtable 同样像个黑盒子,我不知道里面有什么,也是要查手册,当然我知道里面有个 “IsSuccess”,于是我又要手动敲进去,还要用 Equals 和 1 去比较才知道是否成功,你可能会问,为什么不直接返回一个 bool 类型的 true 或 false
  3. 更痛苦的来了,我要拿到取回的数据要写一大串 (DataSource.DataSets["DSGetParamInfo"] as DataSet).Tables[0];
  4. 依次类推,后面的返回对象里面还有 “IsChanged”、“IsUpdate” 等等,并且 IsUpdate 如果是 0 是何意?1 是何意?-1 是何意?亲,查手册吧。
    就是一个简单的取数据,我们就要记忆一大堆所谓内置的 “关键字”,且不说要记忆,每次都要敲也挺累。
    好了,我们再看看微软是底层是如何设计的……
    @#*¥&#@……!
    算了,不找了,你们自己找找会发现,在对你对象设计的语言里,万物皆类,万物皆对象,方法的参数也好返回类型也好都是被精心设计好的有自己结构的 “类”,我们可以很容易发知道这个类里面有什么属性,分别是什么含义,这样,我 们就可以不用去记忆那些装在黑盒子里的 “XXX” 了。
    那么我们看如何来改造现有的 DataSource 来提高我们的编程效率和减少学习周期。

1、请求参数原来是一个 Hashtable,我们把它改成一个结构明确的类

/// <summary>
/// DataSource操作请求类
/// </summary>
public class DsRequest
{
    /// <summary>
    /// 数据集名
    /// </summary>
    public string DataSetName;

    /// <summary>
    /// 逻辑表名,多个表用英文逗号分隔
    /// </summary>
    public string TableNames;

    /// <summary>
    /// 关键字
    /// </summary>
    public Hashtable Keys = new Hashtable();

    /// <summary>
    /// 操作部骤
    /// </summary>
    public List<Act> ActionStep;
}
2、请求结果原来也是Hashtable,我们也把它改成一个结构明确的类
复制代码
/// <summary>
/// DataSource操作结果类
/// </summary>
public class DsResponse
{
    /// <summary>
    /// 是否成功
    /// </summary>
    public bool IsSuccess;

    /// <summary>
    /// 数据源是否改变
    /// </summary>
    public bool IsChanged;

    /// <summary>
    /// 是否需要保存
    /// </summary>
    public DsUpdateState IsUpdate;

    /// <summary>
    /// 是否有必录项为空
    /// </summary>
    public bool IsEmpty;

    /// <summary>
    /// 结果DataSet
    /// </summary>
    public DataSet DataSet;

    /// <summary>
    /// 结果DataTable
    /// </summary>
    public DataTable DataTable;

    /// <summary>
    /// 首行首列值
    /// </summary>
    public object Value;
}
其中是否需要保存之前我们看到返回的情况有-101,不直观,我们又定义了一个枚举,Yes就是保存,No就是不保存,不好吗?

复制代码
/// <summary>
/// 访问用户是否保存数据时的结果枚举
/// </summary>
public enum DsUpdateState
{
    /// <summary>
    /// 是
    /// </summary>
    Yes = 1,
    /// <summary>
    /// 否
    /// </summary>
    No = 0,
    /// <summary>
    /// 用户取消
    /// </summary>
    Cancel = -1
}

好了,请求类和返回类都定义好了,我们来看看如何请求,请求回来如何使用。

下面是改进之后编程的写法,请仔细观察和最开始代码的不同之处。

/// <summary>
/// 获取数据
/// </summary>
private bool GetData()
{
    var qq = new DsRequest();
    qq.DataSetName = "DSGetData";
    qq.TableNames = "T01";
    qq.Keys["UserName"]=AppInfo.UserName; //我知道Keys里面都是关键字,所以大括号{}我不用在这加
    var result = DataSource.GetDataSet(qq);

    /* 取数成功后拿到数据源 */
    if (result.IsSuccess)
    {
        DataTable dt = result.DataTable; //我直接把返回的数据放到了返回类的DataTable属性中了,因为使用频繁,所以这样不是更好吗
    }

    /* 返回结果 */
    return result.IsSuccess;
}

/// <summary>
/// 保存数据
/// </summary>
private bool Save(List<Act> actionStep)
{
    /* 判断是否有修改数据 */
    var qq = new DsRequest();
    qq.DataSetName = "DSGetData";
    qq.TableNames = "T01";
    qq.ActionStep = new List<Act> { Act.CommitEdit };
    var result = DataSource.UpdateDataSet(qq);

    /* 若没有修改数据,返回 */
    if (!result.IsChanged) { return true; }

    /* 询问用户保存数据 */
    if (actionStep.Contains(Act.AskIsUpdate))
    {
        qq.ActionStep = new List<Act> { Act.AskIsUpdate };
        result = DataSource.UpdateDataSet(qq);
        if (result.IsUpdate == DsUpdateState.Cancel) { return false; } //Cancel取消
        if (result.IsUpdate == DsUpdateState.No) { return true; } //No否

        actionStep.Remove(Act.AskIsUpdate);
    }

    /* 保存数据 */
    qq.ActionStep = actionStep;
    return DataSource.UpdateDataSet(qq).IsSuccess;
}

上面代码大家都懂,不需要解读吧。

那么问题又来了,我们的 DataSource.GetDataSet() 方法期望一个 Hashtable 的参数,这样改造成本是不是大了,我们以前已经开发了上百个程序了,都要改吗?

回到最初我们学习的黄皮书,方法的重载是什么,让我们一起读,chong zai,很好。

因为 DataSource 的相关请求处理是在客户端做的,所以我们完全可以写个 GetDataSet(DsRequest request) 的重载然后将 DsRequest 请求转成 Hashtbale,然后调用原来的 GetDataSet(Hashtable ht) 方法,这对编程者来说都是不可见的,所以之前的 GetDataSet(ht) 可以用,新程序你可以用 GetDataSet(qq) 来简化代码。

/// <summary>
/// 获取指定数据集的DataTable
/// </summary>
public DsResponse GetDataSet(DsRequest request)
{
    Hashtable ht = DsRequestToHt(request); //将DsRequest转为Hashtable

    //创建返回对象
    DsResponse result = new DsResponse();

    //获取数据
    if (DataSource.GetDataSet(ht)["IsSuccess"].Equals("0")) return result;

    //成功
    result.IsSuccess = true;
    string dsName = request.DataSetName;
    result.DataSet = DataSource.DataSets[dsName] as DataSet;
    result.DataTable = (DataSource.DataSets[dsName] as DataSet).Tables[0];
    if (result.DataTable.Rows.Count > 0 && result.DataTable.Rows[0][0] != DBNull.Value)
    {
        result.Value = result.DataTable.Rows[0][0];
    }

    return result;
}

/// <summary>
/// 请求类转Hashtable
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private Hashtable DsRequestToHt(DsRequest request)
{
    Hashtable ht = new Hashtable();
    ht["DataSetName"] = request.DataSetName;
    if (!string.IsNullOrWhiteSpace(request.TableNames))
    {
        if (request.TableNames.Contains(","))
        {
            ht["TableNames"] = request.TableNames.Split(',');
        }
        else
        {
            ht["TableNames"] = request.TableNames;
        }

    }
    //关键字(在这里我们把关键字加上大括号)
    if (request.Keys != null && request.Keys.Keys.Count > 0)
    {
        foreach (DictionaryEntry item in request.Keys)
        {
            if (!(item.Key + "").Contains("{"))
            {
                ht["{" + item.Key + "}"] = item.Value + "";
            }
            else
            {
                ht[item.Key] = item.Value + "";
            }
        }
    }

    if (request.ActionStep != null)
    {
        ht["ActionStep"] = request.ActionStep;
    }

    return ht;
}

好了,经过这么改造,写代码就更愉悦了。
然而,看过盗梦空间吗?陀螺还在转,所以梦还没醒来……回到现实,代码还是那样写……

baby,靠你了

houning 回复

baby,靠你了

听说你新买了 C# 书,边学边培训,大城市的同事们就靠你了。

houning 回复

baby,靠你了

你怎么还没换个性感的头像。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册