Reputation: 235
I have a third-party library (dll, created using C#) that contains interfaces
public interface I1 {
void F1();
}
public interface I2 {
void F2();
}
public interface I3 {
void F3();
}
// and so on ...
and contains a class
public class C : I1, I2, I3 // ...
{
public void F1() { } // implement I1.F1();
public void F2() { } // implement I2.F2();
public void F3() { } // implement I3.F3();
// and so on ...
}
I added a reference to this library in my project in VisualStudio and created an instance of class C
C c = new C();
c.F1(); // ok
c.F2(); // ok
c.F3(); // ok
The variable c
allows to call the methods of all interfaces (F1
, F2
, F3
, ...).
To create a variable that allows to call only methods of interface I1
, it is enough to change the type of variable
I1 c = new C();
c.F1(); // ok
// c.F2(); // error is ok
// c.F3(); // error is ok
But now I want to create a variable of some type that allows to call methods of interfaces I1
, I2
and does not allows to call methods of other interfaces
I1_I2 c = new C();
c.F1(); // ok
c.F2(); // ok
// c.F3(); // error is ok
To do this, I created the interface
public interface I1_I2 : I1, I2 { }
However, the compiler does not allow me to make the assignment
I1_I2 c = new C(); // Compile error : Cannot implicitly convert type 'C' to 'I1_I2'.
I tried an explicit conversion
I1_I2 c = (I1_I2)new C(); // Runtime error : InvalidCastException was unhandled.
but this conversion cannot be performed, because class C
does not implement I1_I2
(only I1
and I2
separately).
One of the possible solutions to this problem could be a class-wrapper
public class Wrapper : I1_I2
{
private C _c = new C();
public void F1() { _c.F1(); }
public void F2() { _c.F2(); }
}
// ---------------------------------
I1_I2 c = new Wrapper();
c.F1(); // ok
c.F2(); // ok
// c.F3(); // error is ok
but it means that I must implement each method from both interfaces.
This solution is unacceptable, because in fact these interfaces (I1
, I2
) contains a lot more methods.
So my question is : How to create a variable that will allow me to do this :
c.F1(); // ok
c.F2(); // ok
// c.F3(); // error is ok
?
Upvotes: 2
Views: 221
Reputation: 23220
As you say in your question, you can use a wrapper class but you didn't like it. Another solution is to make the method that use the logic to be a generic method with some constraints.
So let say you have a method that actually look like this:
public void MySuperLogic()
{
C c = new C();
c.F1();
c.F2();
c.F3();
}
You don't want to allow a call to C.F3()
method so a generic method with constraints can help by refactoring the method like below:
public void MySuperLogic<I>(I c)
where I: I1, I2 // <- The generic type parameter should implement interfaces I1 and I2.
{
c.F1();
c.F2();
c.F3(); // <-- CS1061 : Compile time error.
}
CS1061 is a compile time error which tells you this:
CS1061 'I' does not contain a definition for 'F3' and no extension method 'F3' accepting a first argument of type 'I' could be found.
You can call your method like this:
var c = new C();
MySuperLogic(c);
We passed an instance of type C
which implements I3
with F3()
method but because of the constraints defined in MySuperLogic
you're not allowed to use F3()
because it doesn't exist into I1
and I2
.
Upvotes: 2