Переходя по ссылке на поток C#? - PullRequest
0 голосов
/ 16 января 2020

У меня есть метод, который я собираюсь запустить в своем собственном потоке, но не могу понять, как передать ссылку при настройке потока.

 private void ManageConnections(ref List<string> instanceAddresses) 
        {
            int connected = Instances.Count();

            if(instanceAddresses.Count() > connected)
            {
                int instancesToAdd = instanceAddresses.Count() - connected;

                while(instancesToAdd != 0)
                {
                    Channel channel = new Channel(instanceAddresses[instanceAddresses.Count - instancesToAdd], ChannelCredentials.Insecure);
                    var client = new ConfigurationDirectoryService.ConfigurationDirectoryServiceClient(channel);
                    Instances.Add(client);
                    instancesToAdd--;
                }
            }
        }

Желаемое поведение таково, когда исходный Список (instanceAddresses) изменен, этот метод может работать и может настроить нового клиента и добавить его в другой список.

Этот метод вызовет начало потока:

 public CDS_Service(ref List<string> instanceAddresses)
        {
            Thread manageAvaliable = new Thread(CheckAvaliability);
            manageAvaliable.Start();

            if(instanceAddresses.Count() > 0)
            {
                foreach(string instanceAddr in instanceAddresses)
                {
                    Channel channel = new Channel(instanceAddr, ChannelCredentials.Insecure);
                    var client = new ConfigurationDirectoryService.ConfigurationDirectoryServiceClient(channel);
                    Instances.Add(client);
                }

                foreach(CM commandManager in Instances[0].SyncDirectory(new Empty { }).CommandManagers)
                {
                    List<string> commands = new List<string>();

                    foreach(string command in commandManager.Commands)
                    {
                        commands.Add(command);
                    }

                    Directory.Add(new CommandManager(commandManager.Address, commands, commandManager.IsActive));
                }
            }

//Thread would be setup here
        }

И где это построено:

Server server = new Server
            {
                Services = { ConfigurationDirectoryService.BindService(new CDS_Service(ref clientDiscovery.OtherInstances)) },
                Ports = { new ServerPort(addr, PORT, ServerCredentials.Insecure) }
            };

Я также не уверен, является ли это также плохой практикой, передавая ссылку через различные классы, подобные этой.

Возможно ли это / безопасно сделать?

Ответы [ 2 ]

2 голосов
/ 16 января 2020

Вместо использования ref здесь вы должны использовать наблюдаемую коллекцию, например ObservableCollection<T>. List<string> уже передается по ссылке:)

Сначала измените тип clientDiscovery.OtherInstances на ObservableCollection<string>, затем также измените тип параметра конструктора на ObservableCollection<string>. Удалите все ref s, они вам не нужны.

Теперь, перепишите ManageConnections под эту подпись (Вам понадобится using System.Collections.Specialized):

private void ManageConnections(object sender, NotifyCollectionChangedEventArgs e) {

}

Здесь , вы проверите e.NewItems, чтобы увидеть, какие элементы были добавлены в список instanceAddresses, и добавите каждый из них в другой список:

foreach (var item in e.NewItems) {
    Channel channel = new Channel(item, ChannelCredentials.Insecure);
    var client = new ConfigurationDirectoryService.ConfigurationDirectoryServiceClient(channel);
    Instances.Add(client);
}

Возможно, вы захотите что-то сделать, если там удалены предметы также. Если вы хотите справиться с этим, используйте e.OldItems. Это удаленные элементы.

Теперь вместо вызова ManageConnections вы делаете:

instancesToAdd.CollectionChanged += ManageConnections;

Обратите внимание, что это не будет обрабатывать начальные элементы в списке (только последующие изменения будет добавлено), поэтому вы можете обрабатывать начальные элементы сразу после строки выше.

2 голосов
/ 16 января 2020

Вам не нужно ключевое слово ref. List<T> - это класс, который является ссылочным типом, поэтому он уже передан по ссылке.

Ну, если быть точным, вы передаете ссылку, и ТО передается по значению. Ключевое слово ref понадобится вам только в том случае, если вы присвоили ссылку на новый / другой список и хотели, чтобы она была возвращена вызывающей стороне.

Если вы не собираетесь изменять список, то вы, вероятно, вместо этого лучше передать IEnumerable<T>, поскольку это только для чтения. List<T> уже реализует IEnumerable<T>, поэтому вам даже не нужно приводить.

Если вы обращаетесь к списку из разных потоков, тогда Имейте в виду, что это может измениться в ЛЮБОЕ ВРЕМЯ (как в середине итерации). В этом случае вам может потребоваться ConcurrentList<T>, который является как минимум потокобезопасным для добавления / удаления. В качестве альтернативы, если вы только читаете, вам может быть лучше создать «снимок» списка только для чтения в определенной точке, вызвав для него ToArray() или что-то в этом роде и передав его вместо этого.

...