我有两个词典,一个用于我作为主机的文件传输,另一个用于我作为客户端的文件传输。
我正在为我的程序的某个区域执行的代码完全相似,除了引用其中一个或另一个之外。出于这个原因,我试图阻止重复代码,如果可以的话。
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);
}
}
}
}
答案 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;
它有效,因为d1
和d2
的类型匹配(或者从一个到另一个有一个演员)。这是关键。如果三元运算符返回的值的类型不同,则无法推断运算符的返回类型,这就是问题所在。
实际上,你可以将一个或两个操作数显式地转换为一个公共接口(如果有的话),使其工作。
答案 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);
。