如何根据条件将变量赋值为两种不同类型中的一种

本文关键字:同类型 一种 两种 条件 何根 变量 赋值 | 更新日期: 2023-09-27 17:50:32

我有两个字典,一个用于我作为主机的文件传输,另一个用于我作为客户端的文件传输。

我为我的程序的一个区域所做的代码是完全相似的,除了引用这些项中的一个或另一个。因此,我尽量避免重复代码。

public void UpdateFileTransferItems(FileTransferItem.FileTransferRole role)
{
    // If the role is Sender then the variable is fileTransferSessionsAsHost, otherwise it is fileTransferSessionsAsClient.
    var fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost : fileTransferSessionsAsClient;

    foreach (var hostSession in fileTransferSessions)
    {
         Do Work in here.
    }
}

显然三元操作符不工作,但我怎么能创建代码,将做什么,我想做的?如果角色是发送者,我希望变量是对fileTransferSessionsAsHost的引用,否则我希望它是fileTransferSessionsAsClient

我是在用一种迟钝的方式来谈论这个吗?我应该只是复制代码,并有两个if语句吗?

编辑:

如果我想不出更好的办法,这就是我现在必须做的。如果仔细查看,除了名称和引用的字典项之外,每个代码都是相同的。
        public void UpdateFileTransferItems(FileTransferItem.FileTransferRole role)
    {
        if (role == FileTransferItem.FileTransferRole.Sender)
        {
            foreach (var hostSession in fileTransferSessionsAsHost)
            {
                var fileTransferItem = activeFileTransfers.FirstOrDefault(fti => fti.SessionId == hostSession.Key.SessionId);
                if (fileTransferItem == null)
                {
                    activeFileTransfers.Add(new FileTransferItem(hostSession.Key.FileName,
                                                                 hostSession.Key.FileExtension,
                                                                 hostSession.Key.FileLength,
                                                                 FileTransferItem.FileTransferRole.Sender,
                                                                 hostSession.Key.SessionId));
                }
                else
                {
                    fileTransferItem.Update(hostSession.Value.TotalBytesSent,
                                            hostSession.Value.TransferSpeed,
                                            hostSession.Value.TotalBytesSent == hostSession.Key.FileLength);
                }
            }
        }
        else
        {
            foreach (var clientSession in fileTransferSessionsAsClient)
            {
                var fileTransferItem = activeFileTransfers.FirstOrDefault(fti => fti.SessionId == clientSession.Key.SessionId);
                if (fileTransferItem == null)
                {
                    activeFileTransfers.Add(new FileTransferItem(clientSession.Key.FileName,
                                                                 clientSession.Key.FileExtension,
                                                                 clientSession.Key.FileLength,
                                                                 FileTransferItem.FileTransferRole.Sender,
                                                                 clientSession.Key.SessionId));
                }
                else
                {
                    fileTransferItem.Update(clientSession.Value.TotalBytesSent,
                                            clientSession.Value.TransferSpeed,
                                            clientSession.Value.TotalBytesSent == clientSession.Key.FileLength);
                }
            }
        }
    }

如何根据条件将变量赋值为两种不同类型中的一种

为了达到您的目的,两个类需要从相同的基类或接口派生。例如,如果你有一个叫做IFileTransferSessions的通用接口,那么下面的代码应该可以工作:

IFileTransferSessions fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost : fileTransferSessionsAsClient;

或者如果您真的想保留var语法:

var fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost as IFileTransferSessions : fileTransferSessionsAsClient;

注意,您只需要将第一个三级结果强制转换到接口,或者您可以同时执行这两个操作。

var关键字不像VB中的Variant,它在编译时不关心类型是什么。(这更接近c#中的dynamic)它所做的就是从下面的用法中派生类型。对于要派生的两个不同的类,它们必须共享一个公共基类或接口,即使这样,var也需要知道该基类定义才能正常工作。

有几种不同的方法可以解决这个问题。使用接口是最安全、最合理的方法(或者使用基类)。它们实现了相同的属性,所以它们都可以有一个接口来公开这些属性,然后你可以将它们强制转换到接口。

如果你不能(或不愿意)修改类定义来使用接口,那么你也可以使用反射或动态。它们都容易受到运行时错误的影响,这比使用接口得到的编译时错误更糟糕。与反射相比,使用动态具有更清晰的语法,也更容易编写。只需将这两个项强制转换为dynamic,并将它们存储在动态引用中。然后你可以调用它们的必要属性。

dynamic fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? 
    (dynamic)fileTransferSessionsAsHost :
    (dynamic)fileTransferSessionsAsClient;

动态键入信息:http://msdn.microsoft.com/en-us/library/dd264736.aspx

考虑下面的代码。

Dictionary<int, string> d1 = new Dictionary<int, string>();
Dictionary<int, string> d2 = new Dictionary<int, string>();
bool flag = true;
var d = flag ? d1 : d2;

它可以工作,因为d1d2的类型匹配(或者从一个转换到另一个)。这是关键。如果三元操作符返回值的类型不同,则不能推断操作符的返回类型,这就是问题所在。


实际上,您可以显式地将一个或两个操作数强制转换为一个公共接口(如果有的话)以使其工作

如果您至少可以从同一个基类或接口派生hostSession和clientSession,那么您可以通过分解其中的一些来大大减少代码:

public void UpdateFileTransferItems(FileTransferItem.FileTransferRole role)
{
    if (role == FileTransferItem.FileTransferRole.Sender)
    {
        foreach (var hostSession in fileTransferSessionsAsHost)
        {
              UpdateTransfers(hostSession);
        }
    }
    else
    {
        foreach (var clientSession in fileTransferSessionsAsClient)
        {
              UpdateTransfers(clientSession);
        }
    }
}
private void UpdateTransfers(SessionBaseType session)
{
            var fileTransferItem = activeFileTransfers.FirstOrDefault(fti => fti.SessionId == session.Key.SessionId);
            if (fileTransferItem == null)
            {
                activeFileTransfers.Add(new FileTransferItem(session.Key.FileName,
                                                             session.Key.FileExtension,
                                                             session.Key.FileLength,
                                                             FileTransferItem.FileTransferRole.Sender,
                                                             session.Key.SessionId));
            }
            else
            {
                fileTransferItem.Update(session.Value.TotalBytesSent,
                                        session.Value.TransferSpeed,
                                        session.Value.TotalBytesSent == session.Key.FileLength);
            }
}

如果您不能修改会话类以使其具有共同的祖先,那么另一种方法是制作一个暴露必要属性的包装器类,并且您基本上仍然可以使用上述代码,只是您将拥有UpdateTransfers(new SessionWrapper(clientSession));而不是UpdateTransfers(clientSession);