Передача по ссылке на поток C #?

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

 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 ответа


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

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

Теперь 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;

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


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

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

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

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


Есть идеи?

10000