Say I have the following interfaces:
public interface IReturnableAs {
protected String ReturnAs { get; set; }
}
public interface IReturnableAsImage<T> {
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large") {
ReturnAs = "image";
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> {
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
ReturnAs = "json";
IsPretty = isPretty;
return (T)this;
}
}
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo> {...}
Initially, the errors force me to have implementations for the ReturnAs
, ImageResolution
and IsPretty
properties. Making these implementations protected
end up with CS0535
, saying that the properties weren't implemented. On the other hand, making these public
gave me CS8704
, telling that this implementation is not possible.
Other than abstract classes, would there be workarounds for these errors?
First of all, what do you want to achieve? What should Foo.ReturnAs
return? How are you going to use those interfaces?
You can't use ReturnAs
in the other interfaces without inheriting from IReturnableAs
. Once you inherit from that interface though Foo
will have to provide an implementation. When that happens, no matter how you cast Foo
you'll always get its own IReturnableAs
implementation.
Interfaces aren't abstract classes so there can only be one interface member implementation. You can't access different "default" implementations through different interfaces.
Composite result when accessed through IReturnableAs
If you want to return json
or image
for the specific interfaces and image;json
for Foo
overall the best option would be for the interfaces to not inherit from IReturnableAs
, and provide their own ReturnAs
property :
public interface IReturnableAs {
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T>
{
public String ReturnAs =>"image";
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> {
public String ReturnAs =>"json";
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
IsPretty = isPretty;
return (T)this;
}
}
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo> ,IReturnableAs
{
string IReturnableAs.ReturnAs =>"image;json";
String IReturnableAsImage<Foo>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<Foo>.IsPretty { get; set; }=false;
}
The following code :
void Main()
{
var foo=new Foo();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs);
Console.WriteLine(((IReturnableAsJson<Foo>)foo).ReturnAs);
}
Prints:
image;json
image
json
I removed the ReturnAs
setters since the valid value will always be the same for the same interface.
If you want to create a new class that generates JPGs, eg FooJpg
, you can override the default implementation of IReturnableAsImage<T>
, eg :
public class FooJpg : IReturnableAsImage<FooJpg>, IReturnableAsJson<FooJpg> ,IReturnableAs
{
string IReturnableAs.ReturnAs =>"jpg;json";
String IReturnableAsImage<FooJpg>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<FooJpg>.IsPretty { get; set; }=false;
String IReturnableAsImage<FooJpg>.ReturnAs => "jpg";
}
Same result no matter the interface
If you want Foo.ReturnAs
to always return the same value, eg "image;json"
, you can add a default IReturnAs
implementation for single use cases, and override the method for multiple uses :
public interface IReturnableAs {
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T>:IReturnableAs
{
String IReturnableAs.ReturnAs =>"image";
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T>:IReturnableAs {
String IReturnableAs.ReturnAs =>"json";
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
//ReturnAs="json";
IsPretty = isPretty;
return (T)this;
}
}
In this case the IReturnableAsImage
, IReturnableAsJson
interfaces provide an implementation. For this class :
public class Foo : IReturnableAsImage<Foo>
{
String IReturnableAsImage<Foo>.ImageResolution { get; set; }="3";
}
The following code will print image
:
void Main()
{
var foo=new Foo();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs);
}
For a class that uses both interfaces, an explicit IReturnableAs
implementation is needed:
public class FooMulti : IReturnableAsImage<FooMulti>, IReturnableAsJson<FooMulti>
{
String IReturnableAs.ReturnAs =>"image;json";
String IReturnableAsImage<FooMulti>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<FooMulti>.IsPretty { get; set; }=false;
}
In this case all calls will return image;json
:
void Main()
{
var foo=new FooMulti();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<FooMulti>)foo).ReturnAs);
Console.WriteLine(((IReturnableAsJson<FooMulti>)foo).ReturnAs);
}
image;json
image;json
image;json