I have a simple c# question (so I believe). I'm a beginner with the language and I ran into a problem regarding interfaces and classes that implement them. The problem is
I have the Interface iA
interface iA
{
bool method1
bool method2
bool method3
}
and 3 classes that implement the interface: class B, C and D
class B : iA
{
public bool method1
public bool method2
public bool method3
}
if class B had another method that is not in the interface, let's say method4() and I have the following:
iA element = new B();
and then I would use :
element.method4();
I would get an error saying that I don't have a method4() that takes a first argument of type iA.
The question is: Can I have an object of interface type and instantiated with a class and have that object call a method from the class, a method that is not in the interface ?
A solution I came up with was to use an abstract class between the interface and the derived classes, but IMO that would put the interface out of scope. In my design I would like to use only the interface and the derived classes.
Yes, that is possible. You just need to cast the Interface type to the class type like this:
iA element = new B();
((B)element).method4();
As suggested by wudzik, you should check if elemnt is of the correct type:
if(element is B)
{
((B)element).method4();
}
You have to cast the interface type to the class type; usually we do it by means of as:
B b = element as B; // <- try cast element as B
if (!Object.RefernceEquals(null, b)) { // <- element is B or can be legaly interpreted as B
b.method4();
}
The advantage of "as" is that there's only one cast operation, while "is" and (B) have to do two casts.
Without casting you could do this.
interface iA
{
bool method1();
bool method2();
bool method3();
}
interface IFoo : iA
{
bool method4();
}
class B : IFoo
{
public bool method1() {}
public bool method2() {}
public bool method3() {}
public bool method4() {}
}
IFoo element = new B();
element.method4();
NB: Try to use capital I prefix for C# interfaces.
Related
I am trying to get code below running. I want to cast an object of class A to an object of class B, buit i get an error. In theory, the A is a part of B, so I can't see, why this won't work.
I know, that this cast does mean losing some data, but that is exactly what I want.
Is there any way to get this running?
public class Program
{
public static void Main()
{
var b = new B();
var a = (A)b; //Error: Cannot convert type
}
}
public interface IA{}
public interface IB : IA{}
public class A : IA{}
public class B : IB{}
Clearly, B is not of type A and vice versa:
It's impossible to cast B to A. You only can cast to IB or IA types.
You can solve this in multiple ways, one being the way Gilad Green stated in his answer, or by also implementing a conversion method:
public static implicit operator A(B b)
{
//your code to convert from B to A
}
public static implicit operator B(A a)
{
//your code to convert from A to B
}
Since B implements both IA and IB you cannot directly cast to and from one another unless you implement something like the code snippet in this answer.
I'm trying to do the following:
public class A
{
}
public class B
{
}
Somewhere along the project I want to have this:
public class C
{
public T func<T>(T obj) [where T can be either of class A or class B]
{
obj.x = 100;
return obj;
}
}
I've been trying:
public T func<T>(T obj) where T: A, B
but this gives me:
The type class constraint 'B' must come before any other constraint.
Can someone explain me how to make func accept only class A or class B?
Exactly as it's described in the question, this job is better handled by overload resolution:
public class C
{
public A func(A obj)
{
obj.x = 100;
return obj;
}
public B func(B obj)
{
obj.x = 100;
return obj;
}
}
But I understand that A and B may be placeholders for any number of types, and it could get tedious to account for them all. In that case, you'll need a common interface that's supported by each of your classes:
interface IBase
{
int x;
}
public class C
{
public IBase func(IBase obj)
{
obj.x = 100;
return obj;
}
}
Note that at this point we still have no need of generics. Additionally, you may need to support a number of types that won't all fit together under a common interface. In this case, still build the interface and put as many types with that interface as possible. If needed, build another interface for a few more types ... and so on... and then between interfaces and specific types you can handle things with overload resolution.
You need some kind of common base for both the classes, either have them implement the same interface as the below code or have them inherit from same class. You can not have a generic constrained to 2 types.
public interface IFooBar
{
void DoThis();
}
public class Foo : IFooBar
{
public void DoThis()
{
//Do something
}
}
public class Bar : IFooBar
{
public void DoThis()
{
//Do something
}
}
public class C
{
public T func<T>(T obj) where T : IFooBar
{
obj.DoThis();
return obj;
}
}
The generics classes are just like any other class, you can't (and shouldn't) have multiple inheritance of classes, you can inherit one class and multiple interfaces.
in your case you should apply an interface on both classes and restrict the generics on that interface.
you can see some documentation in:
Constraints on Type Parameters (C# Programming Guide)
interface IMarkerInterface{} // there is a such pattern called marker
// interface . No need to have methods if there
// is no need for, A and B can just implement it
public class A: IMarkerInterface
{
}
public class B: IMarkerInterface
{
}
public class C
{
public T func<T>(T obj).Where T:IMarkerInterface
{
obj.x = 100;
return obj;
}
}
public T func<T>(T obj) where T: A, B this means T should extend both A and B , but multiple inheritance is not valid in C# ,so it won't work.
You could do one of the following though :
you could make A and B have a common parent via an interface or an abstract class , but that would be code modification.
since both A and B have a default no-arg constructor you could use where T: new().
Also, you can not do obj.x = 100; as there is no way to guarantee thatT will have a instance variable x.
In the example below, is there a way for a method of the implementing class to explicitly tell the compiler which interface member it implements?
I know it's possible to resolve ambiguity between interfaces, but here it is within one interface.
interface IFoo<A,B>
{
void Bar(A a);
void Bar(B b);
}
class Foo : IFoo<string, string>
{
public void Bar(string a) { }
public void Bar(string b) { } // ambiguous signature
}
I don't think that you can solve that directly by only using one interface because the method signatures may unify for some cases.
If you realy need this feature I think you've to introduce a new interface that will be derived by foo.
public interface IBar<T>
{
void Bar(T t);
}
public interface IFoo<A, B> : IBar<A>
{
void Bar(B b);
}
Now you're able to explicitly implement both interfaces:
public class Foo : IFoo<string, string>
{
void IFoo<string, string>.Bar(string b)
{
Console.WriteLine("IFoo<string, string>.Bar: " + b);
}
void IBar<string>.Bar(string t)
{
Console.WriteLine("IBar<string>.Bar: " + t);
}
}
But if you want to use it you've to cast your instance to the special interface:
var foo = new Foo();
((IFoo<string, string>)foo).Bar("Hello");
((IBar<string>foo).Bar("World");
This prints as expected:
IFoo<string, string>.Bar: Hello
IBar<string>.Bar: World
Hopefully this will help you. I don't think that there is another way of doing that.
It is possible to implement only one interface explicitly so that you only need to cast if you want to call the other method.
You just need to remove the duplicate line:
interface IFoo<A, B>
{
void Bar(A a);
void Bar(B b);
}
class Foo : IFoo<string, string>
{
public void Bar(string a) { }
}
In this case having a single implementation of void Bar(string a) implements both methods of the interface.
Actually calling the interfaces is much harder though. You need reflection.
You can't do that.
Bar() will be ambiguous in this situation. Consider changing the interface methods to BarA(), BarB().
Also, consider making A and B more meaningful names (e.g., IFoo<TKey, TValue>), then your methods could be BarKey() and BarValue().
I would like to have interace A. Which will allow objects of type A generate other objects of type A.
I need the same behavior for type B. In my application is true that all B are also A. So I would like B to be derived from A.
This is my try:
public interface A {
A method1();
}
public interface B : A {
overrride B method1();
void otherMethod();
}
Note that override keyword dosn't compile here. The only way to make the project compile is make the interface B look as follows:
public interface B : A {
//A method1(); /* commented out because it is inherired */
void otherMethod();
}
However I would like to promise by interface B, that objects of this type have method to produce other objects of type B.
Implementation of interface B could look like:
class Foo : B {
B metod1();
}
Where I want B metod1() to be implemantation of B method1() from interface B and I also want the same method to be implementation of A method1() from interface A. I expect the same behavior in all classes implementing interface B. So I don't want to implement method1 each time twice for both interfaces.
I am doing this in c# with interfaces. But I believe that similar question could be interesting even with classes and possibly also in Java.
The only way to do this properly is using generics like this:
public interface A<T> where T : A<T>
{
T method1();
}
Then B looks like this:
public interface B : A<B>
{
void otherMethod();
}
And finally, implementing a class would go like this:
public class Bravo : B
{
public B method1() { return null; }
public void otherMethod() { }
}
However, you can use the new keyword to shadow a method in an interface, but this isn't a great idea as it makes it harder to reason about your code as it breaks normal inheritance.
Try this:
public interface A
{
A method1();
}
public interface B : A
{
new B method1();
void otherMethod();
}
public class Bravo : B
{
A A.method1() { return null; }
public B method1() { return null; }
public void otherMethod() { }
}
That sure is possible, use the new keyword here, not the override and implement the overridden interface explicitly.
Edit:
Adjusted the sample based on your comments. You will still need the explicit interface implementation IFoo IFoo.GetData() { return GetData(); }, but this one has no code on its own, since its just calling he implicit implementation public INewFoo GetData() { return new Foo(); }.
Here is an example:
public interface IFoo
{
IFoo GetData();
}
public interface INewFoo : IFoo
{
new INewFoo GetData();
}
public class Foo : INewFoo
{
IFoo IFoo.GetData() { return GetData(); }
public INewFoo GetData() { return new Foo(); }
}
Is there any type-safe, compile-time checked possibilty of referring to values that implement multiple interfaces?
Given
interface A {
void DoA();
}
interface B {
void DoB();
}
I'm able to write code for objects implementing A or B, but not both. So I've to come up with ugly wrappers:
class ABCollection {
private class ABWrapper : A, B {
private readonly A a;
private readonly B b;
public static ABWrapper Create<T>(T x) where T : A, B {
return new ABWrapper { a = x, b = x };
}
public void DoA() {
a.DoA();
}
public void DoB() {
b.DoB();
}
}
private List<ABWrapper> data = new List<ABWrapper>();
public void Add<T>(T val) where T : A, B {
data.Add(ABWrapper.Create(val));
}
}
Is there a trick to write this code more intuitively without losing type-safety (runtime-casts etc.)?
E.g.
private List<A and B> ...
Edit: This is not about having a list in particular - I just wanted to give a "complete" example with the issue of storing such values. My problem is just how to type a combination of both interfaces (like A & B or A and B).
Another more useful example: List<IDrawable & IMovable> ...
You can do parametric polymorphism like that in C#, but not subtype polymorphism. That is, you can create a polymorphic method like:
void Foo<T>(T t) where T : IFoo, IBar
{
t.Foo();
t.Bar();
}
and then you must pass an object whose type is known at compile time to implement both IFoo and IBar.
But there is no way to say
void Foo(IFoo-and-IBar t)
{
t.Foo();
t.Bar();
}
and then pass in a value that is both an IFoo and an IBar. Neat feature, but not one we support.
Well, as Eric Lippert said, there's no IFoo-and-IBar type you can use as a method parameter type.
However, I was playing around with some ideas and came up with an alternate way of using your wrapper class that may be better. I'll leave that up to you (or whoever else might search for this question) to decide:
CLASSES
public abstract class ABWrapper : IA, IB
{
private readonly IA a;
private readonly IB b;
protected ABWrapper( IA a, IB b ) { this.a = a; this.b = b; }
// Implement methods on IA and IB
}
public sealed class ABWrapper<T> : ABWrapper
where T : IA, IB
{
private ABWrapper( T a, T b ) : base( a, b ) { }
public static implicit operator ABWrapper<T>( T t )
{
if ( t == null ) return null;
return new ABWrapper<T>( t, t );
}
}
EXAMPLE
public class AB : IA, IB { }
void Method( ABWrapper x )
{
}
void Main()
{
AB x = null;
Method( (ABWrapper<AB>) x );
}
The icky thing about this is that you need to do a cast to ABWrapper<T> at every call site. You could also create an extension method ABWrapper ToABWrapper<T>(this T t) where T : IA, IB to replace the cast if that would be more preferable.
It would be cool if the compiler could reason that an implicit conversion from AB to ABWrapper exists via implicit conversions to and from ABWrapper<T>. There's probably a very good reason it doesn't try to do that, however.
However, what you gain is the ability to put ABWrapper all throughout your method parameters without needing to genercize the methods.
I'm not clear on why you'd want to do this. If you did, you could declare a base interface:
interface AorB {}
interface A : AorB {
void DoA();
}
interface B : AorB {
void DoB();
}
and store those in the collection. Of course you'd have to is- or as-cast when retrieving (standard extension methods could help here).
It seems to me that this is a possible violation of SRP, and the collection is doing too much. Alternately the interfaces are too finely-grained.