Когда использовать классы в C#?
Я относительно новичок в языке C#, однако, благодаря большой помощи от поиска в Google и переполнения стека, я уже создал ряд приложений, которые включают работу с Office, системными службами, процессами, WMI, SQL, Linq и Active Directory...
Хотя, несмотря на успех в получении этих приложений, я все еще не уверен во многих вещах на языке C#, таких как хорошая практика кода и использование многих ключевых слов и т. Д.
C# классы; Я знаю, что я могу с ними сделать, я знаю о Конструкторах и Деструкторах, Instantiation и Properties, но я не уверен, когда мне следует их использовать. До сих пор я написал весь свой код в своем файле Form1.cs в различных методах. Эти методы делают разные вещи с совершенно разными API. Это, очевидно, означает, что пытаться поддерживать этот код может быть довольно сложно, и я нахожу все более и более разочаровывающим поиск чего-либо внутри моего Form1.cs
Мой вопрос к вам, ребята, я должен разделить свой код на разные классы? Я пытался разделить вещи, связанные с SqlConnection и SqlCommands, в отдельный класс, но без многократного создания одного и того же экземпляра этого класса в моем Form1.cs, я не вижу, чтобы это было проще или полезнее.
Я пытался собрать новое приложение вместе, но на этот раз сохраняя функциональность в своем собственном классе, я надеялся, что кто-нибудь может сказать мне, что я глуп, и делаю это неправильно, или, по крайней мере, дать мне некоторое руководство.
Это приложение в конечном итоге загрузит мою строку подключения из App.Config, подключится к базе данных SQL и заполнит DataSet несколькими таблицами из базы данных. Это ни в коем случае не функционально, так как я не могу разобраться с проблемой Classes.
Большое спасибо:)
partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string myConnectionString;
private void Form1_Load(object sender, System.EventArgs e)
{
AppConfig cfg = new AppConfig();
if (cfg.loadConfig())
{
myConnectionString = cfg.myConnectionString();
}
if (!String.IsNullOrEmpty(myConnectionString))
{
SQLConn SQL = new SQLConn();
if (SQL.createConnection(myConnectionString))
{
MessageBox.Show("Connected!");
}
}
}
}
class myDataSet
{
DataSet DataSet()
{
DataSet ds = new DataSet();
SQLConn sql = new SQLConn();
return ds;
}
public void fillData()
{
try
{
SqlCommand sqlCmd = new SqlCommand("SELECT * FROM hardware");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
class SQLConn : IDisposable
{
SqlConnection sqlConn;
public bool createConnection(string myConnectionString)
{
sqlConn = new SqlConnection();
sqlConn.ConnectionString = myConnectionString;
try
{
sqlConn.Open();
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return false;
}
public void Dispose()
{
if (sqlConn.State == ConnectionState.Open)
{
sqlConn.Close();
sqlConn.Dispose();
}
}
}
class AppConfig
{
Configuration cfg;
public bool loadConfig()
{
try
{
cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (!File.Exists(cfg.FilePath))
{
MessageBox.Show("No configuration file");
}
return true;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
return false;
}
public string myConnectionString()
{
string connectionString = ConfigurationManager.ConnectionStrings["IT_ProjectConnectionString"].ConnectionString;
return connectionString;
}
}
3 ответа
Принципы, лежащие в основе ООП, говорят более или менее о том, что вы должны как можно больше разбивать вещи, чтобы связанные вещи группировались в своем собственном классе, как, например, вещи SQL в вашем примере. Другой, часто используемый пример - это автомобиль - если вам нужно иметь дело с данными об автомобилях, вы должны создать класс автомобиля, содержащий соответствующие переменные, такие как максимальная скорость, имя, цвет и соответствующие методы, например, например, drive(double distance)
или что-то типа того.
Если вам не нужны разные объекты этого класса и вам нужно одинаковое поведение в нескольких точках, вы можете предотвратить несколько экземпляров несколькими способами: если все точки находятся в вашем Form1
вам нужно создать экземпляр вашего класса только один раз, и вы можете использовать его на протяжении всего Form1
учебный класс. Если вам нужен доступ к нему из разных классов, вы можете либо иметь глобальную переменную (что большинство считают плохой практикой), либо создать класс, к которому вам нужен доступ static
- таким образом, вам вообще не нужно создавать его экземпляр.
Если ваше приложение действительно маленькое, вы можете оставить все это в своем Form1
класс, но, как вы сами заметили, он может очень быстро запутаться и запутаться. Думайте о классах как о возможности сортировать ваш код. Подумайте о том, что с чем связано, и что вы ожидаете найти вместе, и поместите эти вещи в классы. Если вы будете придерживаться этого, вы в конечном итоге получите код, который будет менее расстраивающим, и который имеет четкую и логичную структуру. Вы можете использовать преимущества таких вещей, как наследование, когда все становится более сложным, и вы можете повторно использовать классы, которые делают вещи (опять же, например, базы данных), которые могут вам понадобиться в разных приложениях.
Это очень краткое и очень грубое описание. Я сам не знаю хороших книг по этой теме (кроме тех, которые предназначены для начинающих программистов, что здесь неуместно), но я предлагаю найти одну из них по ООП или найти хорошие вводные статьи по этой теме. Лично я считаю CodeProject хорошим источником статей. Вот один на ООП.
Я использую принцип единой ответственности в качестве руководства для разработки классов. Вот хорошее обсуждение этого, с существенным моментом:
Дело в том, что каждый класс должен реализовывать связный набор связанных функций. Простой способ следовать принципу единой ответственности - постоянно задавать себе вопрос, связан ли каждый метод и операция класса с именем этого класса. Если вы найдете некоторые методы, которые не соответствуют имени класса, вам следует рассмотреть возможность перемещения этих методов в другой класс.
Имея это в виду, я думаю, что вы правы, разделив функциональность вашего примера приложения на отдельные классы. В противном случае вы получите конгломератный класс Form1, который обладает множеством обязанностей: чтение значений конфигурации, подключение к базам данных, чтение данных. Как вы заметили, разделение кода на отдельные классы также облегчает понимание и навигацию программы.
Подумайте о своих классах, инкапсулирующих какую-то функциональность. В вашем случае SQLConn обрабатывает соединения с базой данных, это означает, что этот класс владеет соединением с базой данных, и весь трафик теперь должен проходить через этот класс. Это также означает, что ваш класс myDataSet должен использовать ваш класс SQLConn для всех коммуникаций, поэтому ошибочно создавать экземпляр SqlCommand внутри него.
Я думаю, что вы можете путать экземпляры с классами в вашей реализации. Вы создаете несколько экземпляров класса SQLConn, сначала в вашем методе OnLoad, где вы подключаетесь к базе данных, а затем в своем классе myDataSet. Это не тот же самый класс в классе. Таким образом, ваш класс myDataSet будет использовать SQLConn, который не подключен к базе данных.
Вместо этого вы можете совместно использовать тот же экземпляр, предоставив классу myDataSet экземпляр SQLConn, с которым вы хотите, чтобы он работал:
public myDataSet(SQLConn conn)
{
SQLConn sql = conn;
}
{
SQLConn conn = new SQLConn();
conn.createConnection(...);
myDataSet ds = new myDataSet(conn);
}
Это все еще не очень хороший дизайн, но он показывает, как передать экземпляр вместо прямой ссылки на класс.