如何根据条件将var指定为两种差异类型之一?

时间:2013-01-04 03:05:53

标签: c# ternary-operator var

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

我正在为我的程序的某个区域执行的代码完全相似,除了引用其中一个或另一个之外。出于这个原因,我试图阻止重复代码,如果可以的话。

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);
                }
            }
        }
    }

4 个答案:

答案 0 :(得分:2)

为了满足您的需求,两个类都需要从相同的基类或接口派生。例如,如果您有一个名为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也需要知道该基本定义才能正常工作。

答案 1 :(得分:1)

有几种不同的方法可以解决这个问题。使用接口将是最安全和最合理的方法(或使用基类)。它们实现相同的属性,因此它们都可以具有暴露这些属性的接口,然后您可以将它们转换为接口。

如果您不能(或不会)修改类定义以使用接口,那么您也可以使用反射或动态。这些对运行时错误都是可以理解的,这比使用接口得到的编译时更糟糕。使用dynamic有一个更清晰的语法,比反射更容易编写。只需将两个项目都转换为动态,并将它们存储在动态引用中。然后你可以调用它们的必要属性。

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

有关动态类型的信息:http://msdn.microsoft.com/en-us/library/dd264736.aspx

答案 2 :(得分:0)

考虑这段代码。

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的类型匹配(或者从一个到另一个有一个演员)。这是关键。如果三元运算符返回的值的类型不同,则无法推断运算符的返回类型,这就是问题所在。


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

答案 3 :(得分:0)

如果你至少可以从同一个基类或接口派生出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);
            }
}

如果你不能修改会话类以拥有一个共同的祖先,那么另一种方法是创建一个暴露必要属性的包装类,你仍然可以使用上面的代码,而不是{{ 1}},你有UpdateTransfers(clientSession);