#c# #visual-studio #telnet
#c# #visual-studio #telnet
Вопрос:
Хорошо, итак, я полностью застрял. Мне не хватает навыков поиска, и я не могу найти ничего, что помогло бы мне понять, что мне нужно делать.
У меня есть приложение Telnet. Form1 подключается и предварительно формирует содержимое сокета через класс. Класс ссылается на форму один следующим образом
//form1
telnet tc;
private void connect_Click(object sender, EventArgs e)
{
tc = new telnet (IP, Port);
}
То, что я пытаюсь сделать, это использовать этот же метод в form2. form2 — это окно конфигурации, требующее получения данных с сервера telnet для сохранения в XML-файл. через
//form 1
tc.read();
Я мог бы вызвать новый экземпляр класса telnet, но это было бы пустой тратой ресурсов, и я думаю, что есть лучший способ его закодировать.
Итак, что я хотел бы знать, находясь в form2. Как мне сообщить событию нажатия кнопки для доступа к tc из form1?
До сих пор я не смог понять, как получить ссылку на form1 tc или кнопку connect_click для формы 2.
//form2
private void read_click(object sender, EventArgs e)
{
tc.read(); // how do i call it? or even call a method of form 1 to button click?
... write data from tc.read()
}
Комментарии:
1. После прочтения комментариев я думаю, что забыл включить важную часть того, что делает мое приложение. Я верю, что у меня есть свой ответ, и представленные ответы, я думаю, являются ценными методами, которые выглядят забавными для реализации. Но только для пояснения Форма 1 предоставляет информацию о подключении и команды «Что делать». Форма 2 — это форма настройки, которая создает XML-файл с данными подключения, переменными и т. Д., Которые форма 1 использует для команд. Класс просто содержит информацию о сокете.
Ответ №1:
Я знаю, что это шаг за пределы вашей текущей проблемы, но это будет важно в будущем и решит эту проблему, связанную с тем, где создавать экземпляр класса и как совместно использовать этот экземпляр.
Не создавайте экземпляр telnet
класса ни в одной из форм. Используйте Dependency Injection
вместо этого. Создайте экземпляр Telnet
на верхнем уровне вашего приложения и передайте его обеим формам.
Это поможет вам разделить проблемы в вашем приложении и упростит модульное тестирование вашего приложения в будущем (потому что вы можете создать подделку Telnet
для их использования).
Что-то вроде:
public static void Main(string[] args)
{
// maybe get these from the command line, or from app.config
const string ipAddress = "10.0.0.1";
const string port = "80";
var telnet = new Telnet(ipAddress, port);
var mainForm = new MainForm(telnet);
mainForm.ShowDialog();
}
// ...
public class MainForm : Form
{
private Telnet telnet;
public MainForm(Telnet telnet)
{
this.telnet = telnet;
}
// Todo: Use telnet in other methods
private void ShowSubForm()
{
var subForm = new SubForm(telnet);
subForm.Show();
}
}
Это лучше, чем одноэлементный или статический экземпляр, потому что это позволит вам легче изменять ваше приложение в будущем, позволит вам повторно использовать ваш Telnet
класс в будущем, не ограничит вас наличием только одного Telnet
экземпляра для каждой программы и значительно упростит написание модульных тестов для вашего приложения.код, когда вы дойдете до этой точки.
Если вам нужно получить информацию о том, какой IP и порт использовать из основной формы, используйте шаблон Factory, создайте factory Main
и передайте его в форму. Затем вызовите factory в конструкторе MainForm
:
public class TelnetFactory
{
public Telnet Create(string ipAddress, string portNumber)
{
return new Telnet(ipAddress, portNumber);
}
}
// ...
public class MainForm : Form
{
private TelnetFactory telnetFactory;
private Telnet telnet;
public MainForm(TelnetFactory telnetFactory)
{
this.telnetFactory = telnetFactory;
}
// Called by a UI action of some sort...
private void Connect(string ipAddress, string portNumber)
{
if(this.telnet != null)
{
this.telnet = telnetFactory.Create(ipAddress, portNumber);
}
}
// Todo: Use telnet in other methods
// Todo: Just pass the existing telnet instance to SubForm
}
Если вы создаете обе формы в третьем промежуточном классе, вместо создания одной формы из другой формы, вы все равно можете использовать эти шаблоны. Просто создайте Telnet
экземпляр в этом промежуточном классе или передайте фабрику этому промежуточному классу.
Ответ №2:
Одним из вариантов является создание одноэлементного объекта, которому принадлежат коммуникации.
http://msdn.microsoft.com/en-us/library/ff650316.aspx
Итак, если у вас было что-то вроде:
public class Communicator
{
Telnet m_telnet;
private static Communicator instance;
private Communicator() {m_telnet = new Telnet()}
public static Communicator Instance
{
get {
if (instance == null) {
instance = new Communicator();
}
return instance;
}
public string DoSomething()
{
return m_telnet.DoSomething();
}
}
}
Затем в ваших функциях формы вы могли бы просто:
Communicator.Instance.DoSomething();
Поскольку к этому объекту обращаются разные формы, он не должен быть потокобезопасным. Если это так, вы можете использовать шаблон двойной блокировки.
Комментарии:
1. я думаю, что одноэлементный элемент является излишним. он, вероятно, действительно хочет новый сеанс telnet при каждом нажатии кнопки подключения. сделать свойство member статическим проще, и в данном случае это уместно.
2. @Jason: Нет — это создает связь, когда представления сталкиваются друг с другом. Именно по этой причине MVC существует уже довольно давно, и появляются новые шаблоны, такие как MVVM. Использование представлений, сталкивающихся друг с другом, приводит к созданию спагетти-кода, который сложно изменить и хрупкий. Отделяя связь от ваших представлений, это хороший многоуровневый дизайн.
3. конечно, я хорошо знаком с этими шаблонами, но я все равно не стал бы реализовывать его как одноэлементный. singleton предназначен для обеспечения возврата только одного экземпляра объекта. в этом случае он фактически хочет новый экземпляр сеанса telnet при каждом нажатии кнопки «подключиться». итак, возможно, мы говорим о службе, которая возвращает текущий экземпляр объекта telnet, но предоставляет метод, который позволяет Form1 устанавливать, что это за экземпляр. Пожалуйста, посмотрите мое редактирование
4. Теперь, когда я смотрю на свою реализацию, я предполагаю, что это одноэлементный, но его можно изменить, что важно в данном случае.
5. Вау, это дало мне хорошую возможность начать. Спасибо всем. Чтобы прояснить, что мне нужно, я пытался убедиться, что одновременно с сервером telnet выполняется только одно соединение. Итак, только один экземпляр. В основном потому, что я не хотел переписывать переговоры, проверки и так далее. Но чем больше я думаю об этом, тем лучше использовать новый экземпляр. Но просмотр ваших примеров создания общего класса, ссылающегося на исходный класс, меня интригует. Я мог бы сделать это просто потому, что это выглядит забавно. Я чувствую, что мне также следует изучить этот метод.
Ответ №3:
Почему бы не поместить код из первой формы в свой собственный метод и объявить этот метод как общедоступный статический, например.
public static void connect()
{
tc = new telnet (IP, Port);
}
Комментарии:
1. потому что при этом одна форма указывает на другую, что создает ненужную связь
Ответ №4:
обновление на основе комментария брайанмака. я предлагал статический метод в интересах быстрого выполнения чего-либо. вот более подходящая, не одноэлементная реализация (на основе кода Брайана)
public static class Communicator
{
private static Communicator _instance;
private Communicator() {}
public static Telnet Telnet
{
get
{
if (_instance == null)
{
throw new InvalidOperationException("No telnet session established");
}
return _instance;
}
}
public static void OpenSession(string ip, int port)
{
_instance = new telnet(ip, port);
}
}
// form1
private void connect_Click(object sender, EventArgs e)
{
Communicator.OpenSession(IP, Port);
}
//form2
private void read_click(object sender, EventArgs e)
{
Communicator.Telnet.Read();
}
Комментарии:
1. При этом одно представление формы указывает на другое представление формы, что создает ненужную связь и проблемный код для поддержки с течением времени. Прочитайте о MVC, MVVM и т. Д…