5

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

我为我的程序的一个领域所做的代码是完全相似的,除了引用这些项目中的一个或另一个。出于这个原因,如果可以的话,我会尽量防止重复代码。

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

4 回答 4

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需要知道该基定义才能正常工作。

于 2013-01-04T03:29:09.487 回答
1

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

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

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

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

于 2013-01-04T03:36:59.160 回答
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匹配(或者有一个从一个到另一个的转换)。这是关键。如果三元运算符返回的值的类型不同,则无法推断出运算符的返回类型,这就是问题所在。


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

于 2013-01-04T03:09:08.850 回答
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);
            }
}

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

于 2013-01-04T06:20:50.160 回答