c #, использующий один и тот же экземпляр класса между двумя формами для tcp

#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 и т. Д…