user1017882
user1017882

Reputation:

Combining generic methods and overloads

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

Answers (2)

Der Kommissar
Der Kommissar

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 interfaces 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

StriplingWarrior
StriplingWarrior

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

Related Questions