【问题标题】:Inherited class quagmire, how to make this maintainable code继承类的泥潭,如何让这段代码可维护
【发布时间】:2023-03-11 21:26:01
【问题描述】:

我想创建可维护的代码,但是这种继承情况给我带来了问题。

问题在于我的第二个名为 InitUserExtension 的数据库帮助程序类。

由于 UserExtension 继承自 User,我必须确保将 InitUser 助手中的任何更改镜像到 InitUserExtension。

我真的不喜欢这个,因为它容易出错,有什么解决办法?

我的班级定义:

public class User
{
    public string Name {get; set; }
    public string Age { get; set; }
}

public class UserExtension : User
{
    public string Lastname {get; set; }
        public string Password {get; set; }

}

我的数据库助手:

public static SqlDataReader InitUser(SqlDataReader dr)
{
      User user = new User();

      user.Name = Convert.ToString(dr["name"]);
      user.Age ...
}


public static SqlDataReader InitUserExtension(SqlDataReader dr)
{
      UserExtension user = new UserExtension();


      // note: mirror attributes from User
      user.Name = Convert.ToString(dr["name"]);
      user.Age ...



      user.Lastname = Convert.ToString(dr["lastname"]);
      user.Password = ....;
}

【问题讨论】:

    标签: c# coding-style


    【解决方案1】:

    如何将 Name 等的处理转移到一个方法中(接受一个 User 或一个 T : User),然后从两者中调用它?

    private static void InitUser(User user, SqlDataReader dr)
    { // could also use an interface here, or generics with T : User
      user.Name = Convert.ToString(dr["name"]);
      user.Age ...
    }
    
    
    public static User InitUser(SqlDataReader dr)
    {
        User user = new User();
        InitUser(user, dr);
        return user;
    }
    
    public static UserExtension InitUserExtension(SqlDataReader dr)
    {
      UserExtension user = new UserExtension();
      InitUser(user, dr);
      user.Lastname = Convert.ToString(dr["lastname"]);
      user.Password = ....;
      return user;
    }
    

    作为替代方案,您可以使用泛型减少行数,但增加复杂性:

    private static T InitUserCore<T>(SqlDataReader dr) where T : User, new()
    {
        T user = new T();
        // ...
        return user;
    }
    public static User InitUser(SqlDataReader dr)
    {
        return InitUserCore<User>(dr);
    }
    public static UserExtension InitUserExtension(SqlDataReader dr)
    {
        UserExtension user = InitUserCore<UserExtension>(dr);
        // ...
        return user;
    }
    

    【讨论】:

    • 我有一个 parseRow 方法,然后我可以告诉它我希望它创建什么对象并将值分配给(来自阅读器或 tablerow)
    【解决方案2】:

    为什么不从InitUserExtension 方法调用InitUser。让基初始化处理基类属性,让扩展初始化器处理扩展类属性。

    【讨论】:

      【解决方案3】:

      如果你更喜欢助手,对助手也一样

      public class InitUser
      {
          public InitUser(SqlDataReader dr, User u) { }
      }
      
      public class InitUserExtension : InitUser
      {
          public InitUserExtension(SqlDataReader dr , UserExtension u) : base(dr, u) { }
      }
      

      【讨论】:

        【解决方案4】:

        我不确定您为什么没有将分配代码放在类本身中,但这可能与您获取信息以存储它的方式有关...

        我的解决方案是重写如下:

        public class User
        {
            public string Name {get; set; }
            public string Age { get; set; }
        
            public User(DataReader dr)
            {
               user.Name = Convert.ToString(dr["name"]);
               user.Age ...
            }
        }
        
        public class UserExtension : User
        {
            public string Lastname {get; set; }
            public string Password {get; set; }
        
            public UserExtension(DataReader dr):base(dr)
            {
                user.Lastname = Convert.ToString(dr["lastname"]);
                user.Password = ....;
        
            }
        }
        

        里程可能会因您的情况而异

        这样,调用类似

        var MyExtension = new UserExtension(dr); 
        

        将适当地填充所有字段。

        【讨论】:

        • 在类中重新混合 db 代码:作为猜测......持久性无知和关注点分离 - 即 POCO 不必了解数据库详细信息。
        • 嗯,没错。但是,我看不到他是如何传回他在数据库代码中创建的用户的。如果他在数据库函数之外有声明并传递给它,他也可以链接函数调用,很容易没有问题。
        猜你喜欢
        • 2019-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-22
        相关资源
        最近更新 更多