David Díaz
David Díaz

Reputation: 190

Design problem with C# interfaces

I have recently came to this dilemma: let's say I want to use two libraries each of them defines a interface for a consumer and a consumable:

#region Library A 
// This region represents a library (A) defining some interfaces

/// <summary>
/// Interface to be implemented by any processor of type A
/// </summary>
interface AProcessor
{
    void Process(AProcessable a);
}

/// <summary>
/// Interface to be implemented by any object processable by a processor of type A
/// </summary>
interface AProcessable
{
    int MyPropertyA { get; set; }
}
#endregion


#region Library B
// This region represents a library (B) defining some other interfaces

/// <summary>
/// Interface to be implemented by any processor of type B
/// </summary>
interface BProcessor
{
    void Process(BProcessable a);
}

/// <summary>
/// Interface to be implemented by any object processable by a processor of type B
/// </summary>
interface BProcessable
{
    int MyPropertyB { get; set; }
}
#endregion

Then, on my application, I implement a consumable type that implements both consumable interfaces from each library:

/// <summary>
/// A type processable by processors of type A and processors of type B.
/// </summary>
class Processable :
    AProcessable,
    BProcessable
{
    // Implements interface AProcessable
    public int MyPropertyA { get; set; }

    // Implements interface BProcessable
    public int MyPropertyB { get; set; }
}

And I implement a consumer type capable of consume objects of type Processable, which implements AProcessable and BProcessable:

/// <summary>
/// A processor that implements an A-type processor and a B-type processor.
/// </summary>
class Processor : 
    AProcessor, 
    BProcessor
{
    // I thought that Process method would implement AProcessor.Process() and
    // BProcessor.Process() as it expects a Processable object as parameter which
    // implements AProcessable and BProcessable, but it doesn't.
    // Compiler rises an error telling that Processor doesn't implement neither
    // AProcessor.Process() nor BProcessor.Process()
    /*
    public void Process(Processable a)
    {
        throw new NotImplementedException();
    }
    */


    // Implementing both methods does not work because it creates ambiguity: when
    // we call Processor.Process(p) being "p" a Processable object the compiler 
    // doesn't know if it has to call Processor.Process(AProcessable) or
    // Processor.Process(BProcessable).
    /*
    public void Process(AProcessable a)
    {
        throw new NotImplementedException();
    }

    public void Process(BProcessable a)
    {
        throw new NotImplementedException();
    }
    */
}

¿What's my design error and what would be the correct approach?

Thanks in advance.

Upvotes: 2

Views: 1059

Answers (5)

Francesco Baruchelli
Francesco Baruchelli

Reputation: 7468

I don't think that explicit interface implementation is needed here, since there is no collision between the signatures of the two processing methods (the type of the argument is AProcessable for AProcessor and BProcessable for the second). Since I immagine that for Processable instances you want both the processing to be executed, I would implement it this way:

public class Processor : AProcessor, BProcessor
{
    #region AProcessor Members

    public void Process(AProcessable a)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    #endregion

    #region BProcessor Members

    public void Process(BProcessable a)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    #endregion

    public void Process(Processable a)
    {
        Process((AProcessable)a);
        Process((BProcessable)a);
    }
}

Upvotes: 1

Paul Carroll
Paul Carroll

Reputation: 1887

Everyone has provided fine explainations for the technical reasons why the code isn't working, however I assume you understand these as your question asked what the design issue is and how to solve it.... so I'll add my 2c into the mix.

Basically you are trying to two mix two otherwise completely distinct concepts into one logical controlling piece of code (the Processor class).

By defining two different things that can be processed and two means by which processors of those things must behave you are setting about defining a system that processes two distinct things in completely different ways... therefore they are not the same and can't be combined.

As for another solution on how to "fix" the problem (I use the word fix lightly as it's hard to suggest an alternate solution without knowing the context of the problem you solving) you really need to find a way to represent the two processable types and processors in a common way.... or just not mix the two concepts in the concrete Processor implementation.

Knowing more about the actual context of the problem would help us give a more accurate suggestion! :)

Good luck!

Upvotes: 0

Adam Houldsworth
Adam Houldsworth

Reputation: 64467

You are looking for Explicit Interface implementations. This link has a tutorial:

http://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx

Basically, the method signature shows the interface type:

void BProcessor.Process(BProcessable b)
{

}

And can only be accessed with a direct reference to BProcessor:

BProcessor b;
b.Process(null);

An inferred reference to BProcessor will not work with explicit implementations:

Processor p;
p.Process(new BProcessable()); // This won't compile.

This allows you to implement interfaces that have conflicting member names. If they have conflicting type names, you then need to start looking into namespace conflicts.

You'll notice an explicit implementation because when you get Intellisense for Processor it will be missing Process(BProcessable b).

If your code for handling process happens to be shared, you can do the following:

public void Process(Processable p)
{

}

void AProcess.Process(AProcessable a)
{
    Process((Processable)a);
}

void BProcess.Process(BProcessable b)
{
    Process((Processable)b);
}

However, personally I'd avoid this type of forward casting as you aren't guaranteed (other than you being in full control of the code) to get given a Processable type.

Upvotes: 4

Schroedingers Cat
Schroedingers Cat

Reputation: 3129

In your first attempt, with one method, you are not implementing the precise definition form the interface, which does not want a Processable object as a parameter, but an AProcessable and BProcessable, depending on which one you want.

The second, as others have pointed out, needs to use explicit implementations, so that you can clearly define which of the two you want to call.

If you want to call both of them, then you need to make two separate calls - you could implement a method Process wihtin the class, and call AProcessable.Process and BProcessable.Process. But it has to be done explicitly, not just through inheritance and interfaces.

Upvotes: 0

Anders Abel
Anders Abel

Reputation: 69250

Use explicit interface implementations:

void AProcessor.Process(AProcessable a)
{
    throw new NotImplementedException();
}

void BProcessor.Process(BProcessable a)
{
    throw new NotImplementedException();
}

Using explicit interface implementations disable automatic lookup of what method to call. When you call those methods you need to cast the object to an interface:

Processor p;
Processable pa;
((AProcess)p).Process(pa);

Except for handling this situation with conflicting names/method signatures explicit implementations can also be used to hide (or at least make it harder to use) methods that are required by an interface, but isn't making sense for a specific class.

Upvotes: 2

Related Questions