Reputation:
I have the following method:
public void Set<T>(IEnumerable<T> records)
{
foreach (var record in records)
{
Set(record);
}
}
I would like either one of the following Set
methods to be called, depending on T
:
public void Set(RecordType1 record)
{
// Some RecordType1 logic
}
public void Set(RecordType2 record)
{
// Some logic applicable to RecordType2 only
}
Hopefully, you can see that I'm attempting allow which Set
method to called to be inferred at runtime. This "isn't working" (i.e. won't compile as it's expecting RecordType1
).
Question
How can I keep this kind of structure without testing for a type before sending the records off to the Set
method?
Upvotes: 3
Views: 158
Reputation: 5953
Why don't you create an interface (IRecordType
), allow RecordType1
and RecordType2
to inherit it, then move the main logic of each Set
method to the interface.
public interface IRecordType
{
void Set(...);
}
public void Set(IEnumerable<IRecordType> records)
{
foreach (var record in records)
{
record.Set(...);
}
}
This is a more maintainable solution. And it also allows for better polymorphism.
Edit: Resource to look at: https://msdn.microsoft.com/en-us/library/3b5b8ezk%28v=vs.90%29.aspx
Also, little sidebar: with interface
s you can not only share certain methods, but properties and events, as well. If RecordType1
and RecordType2
share several common properties, you can add those properties to the interface
, and then use IRecordType
wherever you would have previously needed to distinguish between the two for use of these properties, methods or events. Likewise, the code inside any of those properties, methods or events is permitted to rely on other properties, methods, events or fields that are specific to the object itself. This is the purpose of Object-Oriented languages (C#) and polymorphism.
Edit: As a result of the discussion in the comments, I also wanted to add more information about the decision between using an OOP approach (interface
, abstract class
, class
) and the dynamic
approach StriplingWarrior suggested:
If you don't have access to the actual implementation details of RecordType1
or RecordType2
, or you are unable to alter the design of your application (due to the impeding reliance on the Set(RecordType1)
and Set(RecordType2)
methods, you may find it more fruitful to take his approach of using dynamic
. There are also other options out there that we may not have thought of - you could always give one of them a go. The downside to the dynamic
approach is that it requires .NET 4.0.
Also, more considerations: if you do have access to RecordType1
and RecordType2
implementation details, but cannot change Set(RecordType1)
and Set(RecordType2)
as far as definition, you could always modify the body of them:
public void Set(RecordType1 record)
{
record.Set(...);
}
public void Set(RecordType2 record)
{
record.Set(...);
}
This preserves the ENTIRE application structure, while also decreasing code maintenance and allowing for polymorphism.
Upvotes: 13
Reputation: 156524
If you're positive that every item in the given collection will match a method signature, you can cast the values as dynamic
and let the runtime figure out what to bind it to:
foreach (var record in records)
{
Set((dynamic)record);
}
However, this is highly error prone, and I'd recommend you take a hard look at what you're really trying to accomplish. There's most likely a better pattern to accommodate your needs.
Upvotes: 7