通过引用传递给线程 C#?

Passing by reference to a thread 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) }
            };

我也不确定像这样通过不同的 类 传递 ref 是否也是一种不好的做法。

这是possible/safe要做的吗?

您不需要 ref 关键字。 List<T> 是一个 class ,它是一个引用类型,所以它已经通过引用传递了。

嗯,准确地说,您传递的是引用,而且是按值传递的。如果您将引用分配给新的/不同的列表并希望将其传递回调用者,则只需要 ref 关键字。

如果您不打算更改列表,那么您最好传递 IEnumerable<T>,因为它是只读的。List<T> 已经实现了 IEnumerable<T>,因此您甚至不需要投射。

如果您从不同的线程访问列表,请注意它可能会随时更改(比如迭代到一半)。在这种情况下,您可能需要一个 ConcurrentList<T>,它至少对 add/removes 是线程安全的。或者,如果你只是阅读,你可能会更好地通过在某个点上调用 ToArray() 或其他东西来创建列表的只读 "snapshot" 并传递它。

您不应在此处使用 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;

请注意,这不会处理列表中的初始项(只会添加后续更改),因此您可能希望在上一行之后直接处理初始项。