为什么我的 stopwatch/timespan 没有在整个方法中保留其信息?

Why is my stopwatch/timespan not retaining its information throughout methods?

我目前正在处理一个涉及抽象 classes 和秒表的问题。我有两个 classes,SQL 和 Oracle。它们都采用一个字符串作为连接代码(这些东西实际上没有做任何事情,但我试图让它有点现实)。我想启动秒表,然后以不同的方法停止它 - 但时间跨度总是显示 00:00...

我是否正确访问了父 class 的属性?

我已经尝试在不同的地方初始化我的秒表和时间跨度。

public class Program
    {
        public static void Main(string[] args)
        {
           // ConnectionManagement management = new ConnectionManagement();
           // management.SetUpOptions();


        }
    }

    public class ConnectionManagement
    {
        public void SetUpOptions()
        {
            while (true)
            {
                SqlConnection sqlGatherer = new SqlConnection("placeholder");
                OracleConnection oracleGatherer = new OracleConnection("placeholder");

                Console.WriteLine("1. Open an SQL connection.");
                Console.WriteLine("2. Close an SQL connection.");
                Console.WriteLine("3. Open an Oracle connection.");
                Console.WriteLine("4. Close an SQL connection.");
                string choice = Console.ReadLine();

                if (choice == "1")
                {
                    Console.WriteLine("Enter your connection string.");
                    string enteredConnectionString = Console.ReadLine();
                    sqlGatherer.ConnectionString = enteredConnectionString;
                    sqlGatherer.OpenConnection();
                }
                else if (choice == "2")
                {
                    sqlGatherer.CloseConnection();
                }
                else if (choice == "3")
                {
                    Console.WriteLine("Enter your connection string.");
                    string enteredConnectionString = Console.ReadLine();
                    oracleGatherer.ConnectionString = enteredConnectionString;
                    oracleGatherer.OpenConnection();
                }
                else if (choice == "4")
                {
                    oracleGatherer.CloseConnection();
                }
                else
                {
                    Console.WriteLine("That was not a valid option.");
                }
            }

        }
    }

    public abstract class DataBaseConnection
    {

        public string ConnectionString { get; set; }
        public TimeSpan Timeout { get; set; }
        public Stopwatch OracleStoppy { get; set; }
        public Stopwatch SqlStoppy { get; set; }
        public abstract void OpenConnection();
        public abstract void CloseConnection();

    }

    public class SqlConnection : DataBaseConnection
    {

        private bool CurrentConnection = false;

        public SqlConnection()
        {
            Timeout = new TimeSpan();
            SqlStoppy = new Stopwatch();
        }

        public SqlConnection(string connectionString)
        {

            Timeout = new TimeSpan();
            SqlStoppy = new Stopwatch();
            if (connectionString == null || String.IsNullOrWhiteSpace(connectionString))
            {
                throw new ArgumentException("Program has an invalid SQL connection string.");
            }
            else
            {
                this.ConnectionString = connectionString;
            }
        }

        public override void OpenConnection()
        {
            if (CurrentConnection == true)
            {
                throw new Exception("A connection has already been established.");
            }
            else
            {
                Console.WriteLine("SQL connection established.");
                SqlStoppy.Start();
                CurrentConnection = true;

            }

        }

        public override void CloseConnection()
        {
            if (CurrentConnection == false)
            {
                SqlStoppy.Stop();
                TimeSpan reportedTimeout = Timeout;
                Console.WriteLine("Connection closed. \nThe connection was active for {0}", reportedTimeout);
                SqlStoppy.Reset();
                CurrentConnection = false;

            }
            else
            {
                throw new Exception("There is no SQL connection to close.");
            }

        }
    }

    public class OracleConnection : DataBaseConnection
    {
        private bool CurrentConnection = false;

        public OracleConnection()
        {
            Timeout = new TimeSpan();
            OracleStoppy = new Stopwatch();
        }

        public OracleConnection(string connectionString)
        {
            Timeout = new TimeSpan();
            OracleStoppy = new Stopwatch();
            if (connectionString == null || String.IsNullOrWhiteSpace(connectionString))
            {
                throw new Exception("Program has an invalid Oracle connection string.");
            }
            else
            {
                this.ConnectionString = connectionString;
            }
        }
        public override void OpenConnection()
        {
            if (CurrentConnection == true)
            {
                throw new Exception("A connection has already been established.");
            }
            else
            {
                Console.WriteLine("Oracle connection established.");
                OracleStoppy.Start();
                CurrentConnection = true;
            }

        }

        public override void CloseConnection()
        {
            if (CurrentConnection == false)
            {
                throw new Exception("There is no Oracle connection to close.");
            }
            else
            {
                OracleStoppy.Stop();
                this.Timeout = OracleStoppy.Elapsed;
                Console.WriteLine("Connection closed. \nThe connection was active for {0}", Timeout);
                OracleStoppy.Reset();
                CurrentConnection = false;
            }

        }
    }

在我关闭一个打开的连接后,该方法应该打印它打开了多长时间,或者秒表持续时间。同样的问题发生在我的 CurrentConnection 变量上,所以我把它作为私有变量放在每个 class 中。但是,让父 class 这样的父 class 具有其子 class 可以与之交互的共同属性的意义不是吗?

问题

我看到在 oracle 中你有:

this.Timeout = OracleStoppy.Elapsed;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", Timeout);

但在 sql:

TimeSpan reportedTimeout = Timeout;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", reportedTimeout);

这应该是

this.Timeout = SqlStoppy.Elapsed;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", Timeout);

不是吗?

建议

你使用了父级 class,所以你不需要两个秒表,只需要一个,否则继承是无用的,你重复代码。

你也应该考虑删除一些 setter。

并移动重复的 CurrentConnection,作为保护。

这应该是:

public abstract class DataBaseConnection
{
    protected bool CurrentConnection;

    public string ConnectionString { get; }
    public TimeSpan Timeout { get; }
    public Stopwatch Stoppy { get; }
    public abstract void OpenConnection();
    public abstract void CloseConnection();

    public DataBaseConnection()
    {
      Timeout = new TimeSpan();
      Stoppy = new StopWatch();
    }
}

构造函数之间也使用调用模式:

public OracleConnection()
{
  ...
}

public OracleConnection(string connectionString)
  : this()
{
  ...
}

你重复了太多相同的代码,你真的应该重构和更好地抽象东西。

当代码重复时,您可以:

  • 创建一个方法并调用它,而不是重复代码。

  • 有时您可以将其移动到父级 class。

当变量在子 classes 中重复时,您可以删除它们以在父 class.

中只有一个

您可以使用 publicprivateprotectedinternalabstractvirtualoverride...

您还应该重命名一些变量,使其更加一致和连贯。

规则是名称必须简单并且准确指定它是什么。

例如 Chrono 可能比 Stoppyindex 更好,或者 indexRowi 更好。

所以这里 DurationElapsed 可能比 Timeout 更好,后者指示停止连接尝试的延迟。

另外因为 classes 被命名为 Connection 你不需要指定 OpenConnectionCloseConnection: OpenClose足够了。

也许你会发现这很有用:

What is polymorphism