Reputation: 688
I have two dictionaries, one for my file transfers I have as a host, and one for my file transfers I have as a client.
The code I'm doing for one of the areas of my program is entirely similar, with exception of referencing one of these items or the other. For this reason, I'm trying to prevent duplicating code if I can.
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.
}
}
Obviously the ternary operator doesn't work, but how can I create code that will do what I am trying to do? If the role is of a sender, I want the variable to be a reference to fileTransferSessionsAsHost
, otherwise I want it to be fileTransferSessionsAsClient
.
Am I going about this in an obtuse way? Should I just duplicate the code and have two if statements?
EDIT:
This is what I'm having to do right now, if I can't figure out a better way. If you look, the code is identical for each one, with exception of the names and dictionary items reference.
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);
}
}
}
}
Upvotes: 6
Views: 4680
Reputation: 101700
If you can at least derive both hostSession and clientSession from the same base class or interface, then you can greatly reduce the code by factoring some of it out:
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);
}
}
If you can't modify the session classes to have a common ancestor, then the other approach would be to make a wrapper class that exposes the necessary properties, and you could still essentially use the above code except that instead of UpdateTransfers(clientSession);
, you'd have UpdateTransfers(new SessionWrapper(clientSession));
.
Upvotes: 0
Reputation: 22372
There are a couple different ways to solve this. Using interfaces would be the safest and most reasonable approach (or using a base class). They implement the same properties so they could both have an interface that exposes those properties then you could cast them to the interface.
If you cannot (or willnot) modify the class definitions to use interfaces then you can also use reflection or dynamic. These are both suseptible to runtime-errors which is worse then compile-time that you would get by using interfaces. Using dynamic has a little cleaner syntax and be easier to write than reflection. Just cast both items to dynamic and store them in a dynamic reference. Then you can call the necessary properties on them.
dynamic fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ?
(dynamic)fileTransferSessionsAsHost :
(dynamic)fileTransferSessionsAsClient;
Information on dynamic typing: http://msdn.microsoft.com/en-us/library/dd264736.aspx
Upvotes: 2
Reputation: 34793
In order for what you want, both classes need to derive from the same base class or interface. For instance, if you have a common interface called IFileTransferSessions
, then the following code should work:
IFileTransferSessions fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost : fileTransferSessionsAsClient;
or if you really want to keep the var
syntax:
var fileTransferSessions = role == FileTransferItem.FileTransferRole.Sender ? fileTransferSessionsAsHost as IFileTransferSessions : fileTransferSessionsAsClient;
Note, you only need to cast the first tertiary result to the interface, or you can do both.
The var
keyword is not like Variant
from VB where it doesn't care what the type is at compile time. (that's closer to dynamic
in C#) All it does is derive the type from the following usage. For two different classes to be derived, they must share a common base class or interface, and even then var
needs to know about that base definition to work properly.
Upvotes: 3
Reputation: 18543
Consider this code.
Dictionary<int, string> d1 = new Dictionary<int, string>();
Dictionary<int, string> d2 = new Dictionary<int, string>();
bool flag = true;
var d = flag ? d1 : d2;
It works, as the types of d1
and d2
match (or there is a cast from one to another). This is the key. If the types of the values returned by the ternary operator differ, it cannot infer the return type of the operator and that is the problem.
Actually you could explicitly cast one or both of the operands to a common interface (if there is one) to make it work.
Upvotes: 0