In C# I'm in a scenario with the following types provided by the environment:
public interface IFoo {
}
public abstract class Base {
}
public class Derived : Base, IFoo {
}
public class Arbitrary {
public Base GetBase() { }
}
Here's what I've written in addition to this. Note that I can guarantee in my code that Arbitrary.GetBase() will always return an instance of Derived.
public class Arbitrary2 : Arbitrary {
public IFoo GetDerived() {
return (IFoo)base.GetBase();
}
}
However this code fails with the message "Cannot convert type 'Base' to 'IFoo'".
But if I do this then it works:
public class Arbitrary2 : Arbitrary {
public IFoo GetDerived() {
Object baseAsObject = base.GetBase();
return (IFoo)baseAsObject ;
}
}
Why is this upcast to Object necessary before I downcast it to IFoo? The two pieces of code are functionally identical, and the latter will reliably crash at runtime if the cast is invalid. I don't understand why the compiler complains.
You don't need to do this. Your code should work, as is. See this program for details:
using System;
public interface IFoo { }
public abstract class Base { }
public class Derived : Base, IFoo { }
public class Arbitrary {
public Base GetBase() { return new Derived(); }
}
public class Arbitrary2 : Arbitrary {
public IFoo GetDerived() {
return (IFoo)base.GetBase();
}
}
class Program
{
static void Main(string[] args)
{
Arbitrary2 test = new Arbitrary2();
IFoo check = test.GetDerived();
Console.WriteLine(check.GetType().Name);
Console.WriteLine("Press key to exit:");
Console.ReadKey();
}
}
Your GetBase() method returns Base, which does not implement IFoo.
Base can't be converted to IFoo because Base doesn't have anything to do with IFoo:
public abstract class Base { }
Based on this declaration, there could very well be instances of Base which aren't of type IFoo. Indeed, based on this declaration the compiler has absolutely no reason to assume that any given instance of Base would ever implement IFoo.
Derived implements IFoo:
public class Derived : Base, IFoo { }
But you're not returning a Derived, you're returning a Base. By polymorphing it through Object you're effectively "tricking" the compiler. You're telling it that you know more than it does and it should listen to you. This can be fine, as long as you do in fact know more than the compiler does. And what you know that the compiler doesn't know is that every instance of Base is going to be able to polymorph to IFoo.
In that case, why not just implement IFoo on Base? That way you'd be sharing your knowledge with the compiler and everyone will be happy.
The reason the compiler disallows the explicit cast is that Base doesn't implement IFoo.
If you can guarantee that GetBase() will always return a Derived, then you can just insert a cast to Derived prior to the IFoo cast:
public class Arbitrary2 : Arbitrary {
public IFoo GetDerived() {
return (IFoo)(Derived)base.GetBase();
}
}
Of course this will throw at run-time if you're mistaken. Alternatively, you can use an as cast will just return null if it fails:
public class Arbitrary2 : Arbitrary {
public IFoo GetDerived() {
return base.GetBase() as IFoo;
}
}
Arbitrary.GetBase() returns an instance of Base. Base's hierarchy does not contain IFoo.
At runtime, yes, your object is a Derived instance, but based on what the compiler knows--class relationships--there isn't a connection and therefore a way to cast from Base to IFoo as you are trying in your first method.
Can't you just write
public class Arbitrary2 : Arbitrary {
public IFoo GetDerived() {
return (Derived)this.GetBase();
}
}
The compiler will see the connection between Derived and Base, so the explicit cast to Derived ought to be OK. Then any Derived is surely an IFoo, so there's no need to cast an additional time (that conversion is implicit).
Don't use the base. keyword. Either say this. (as above) or leave out.
EDIT: Also, your original code did compile, but my version might be a bit easier to read.
Related
Is it possible to create an abstract method that must return an instance of the derived class? I can do this:
abstract class Base
{
public abstract Base GetObj();
}
class Derived : Base
{
public Derived() { }
public override Base GetObj()
{
return new Derived();
}
}
But I was wondering if there was a way to do it such that Derived::GetObj() is forced to return a Derived?
Thanks.
Using generics should make this possible:
abstract class Base<T>
where T : Base<T>
{
public abstract T GetObj();
}
class Derived : Base <Derived>
{
public Derived() { }
public override Derived GetObj()
{
return new Derived();
}
}
You could even simplify this even more (if all of the derived instances are created with default constructors):
abstract class Base<T>
where T : Base<T>, new()
{
public static T GetObj()
{
return new T();
}
}
class Derived : Base<Derived>
{
public Derived() { }
}
What you have is almost but not quite exactly an abstract factory. I will first say that you should leave it up to the implementers of the derived classes to get it right, or simply trust that they will.
Another answer has shown what is known as the curiously recurring template pattern. It is where you have a base class that tries to use the type system to enforce that derived types use itself at certain input or output positions.
public abstract class Foo<T> where T : Foo<T>
public class Bar : Foo<Bar>
This idea might work in other languages. It works in C# only so far as people use it correctly. With the above definition of Bar, now I can also have
public class Baz : Foo<Bar>
Which is perfectly legal. Bar is a Foo<Bar>, which is all that is required for Baz to use it. Nothing requires Baz to actually use Foo<Baz>.
The type system in C# simply cannot enforce what you would like enforced. Even with this pattern in place, you are still in the same position as before. You still have to trust the implementers of the derived classes to do it correctly.
For more on this topic, you might read this blog.
Here's a paraphrasing of what I want to do:
public class MyClass
{
public T GetFoo<T>() : where T : class, MyInterface
{
if (typeof(T) == typeof(Class1)
{
return new Class1() as T;
}
else if (typeof(T) == typeof(Class2))
{
return new Class2() as T;
}
else
{
return default(T);
}
}
private interface MyInterface {} // This is actually empty, it doesn't do anything except limit the types that can be passed to GetFoo()
public class Class1 : MyInterface
{
// Stuff
}
public class Class2 : MyInterface
{
// Other Stuff
}
// there are many more such classes that all inherit from MyInterface
}
So, I've got a public class with a public method. The method accepts a generic type parameter. But I want to limit the type of T that it accepts, so that's why it's using the MyInterface.
Of course that fails to compile because MyInterface is private. It throws an "Inconsistent accessibility: constraint type is less accessible than " error.
But here's why I want it to work this way:
Each of the Class1, Class2, etc are declared public, so that others can use them. But I want to restrict others from being able to declare their own such classes and pass them to the GetFoo() method. Because that will break GetFoo(), so that's why I want MyInterface to be private.
If I make MyInterface public, of course it will compile and everything will work just fine. But I need to be able to prevent others from declaring their own classes and inheriting MyInterface and passing that to GetFoo().
I want to allow callers to do this:
Class1 userFoo = GetFoo<Class1>();
I want to PREVENT callers from doing this:
Class UserClass : MyInterface {}
...
UserClass userFoo = GetFoo<UserClass>();
Edit: Thanks for all the very fast replies. Yes I know that's not the purpose of Interface's, it just seemed to make sense to me at the time. I am certainly open to a more elegant solution if one exists.
You cannot. This is fundamentally impossible. By making the interface private, the caller effectively does not know whether a class implements that interface. But by using it in a type constraint, you do require the caller to know whether a class implements that interface.
What you could do is use a common base class: even though that class has to be public, you can prevent others from deriving from it.
public class Base {
internal Base() { }
}
public interface IBase { }
public sealed class Class1 : Base, IBase {
...
}
public sealed class Class2 : Base, IBase {
...
}
public T GetFoo<T>() where T : Base, IBase {
...
}
The IBase interface is to make sure that GetFoo<Base> will be rejected. Class1 and Class2 are sealed to prevent others from deriving from those.
However, this approach can only work if Class1 and Class2 are supposed to have a common base class.
I encourage to re-think your design, though. Almost always, if your generic code has a bunch of typeof(T) == typeof(SomeConcreteClass) conditionals, that's a strong indication that you'd have been better off creating separate methods for each concrete type. But there are exceptions, and I won't rule out the possibility of your code being one of the exceptions.
It makes no sense at all to create a class that implements an interface and to try and hide the abstraction that the interface is offering to you.
OO is not about programming towards objects, what you are definitely trying to do, but about programming towards interfaces, and you are trying to hide them.
Better think of a different approach.
This code works and compiles:
public class MyClass<T> where T : class, IMyInterface
{
public T GetFoo()
{
if (typeof (T) == typeof (Class1))
{
return new Class1() as T;
}
else if (typeof (T) == typeof (Class2))
{
return new Class2() as T;
}
else
{
return default(T);
}
}
}
public interface IMyInterface {} // This is actually empty, it doesn't do anything except limit the types that can be passed to GetFoo()
public class Class1 : IMyInterface
{
// Stuff
}
public class Class2 : IMyInterface
{
// Other Stuff
}
// there are many more such classes that all inherit from MyInterface
And Main method which works fine:
static void Main(string[] args)
{
var a1 = new MyClass<Class1>();
var a2 = a1.GetFoo();
}
Ok, I have a number of different classes deriving from a base class.
This base class is an abstract containing commom methods.
One of the methods is a Copy method, wich should be present in all derived classes, so, I've put it in the base class.
BUT, I want it to return the derived type not the base nor object.
The solution I got for that, is using a type paramter:
abstract class CopyableClass<T>
{
public abstract T Copy();
}
class DerivedClass : CopyableClass<DerivedClass>
{
public override DerivedClass Copy()
{
//do what is needed for copy and return a new DerivedClass
}
}
So, the main purpose here is to
Remove the type parameter in the base class and still make the method return the corresponding derived type.
One workaround.
The best thing I could do so far is one of the comments below, but it still uses a generic parameter
abstract class BaseClass
{
//base methods not related to deriving type
}
interface ICopyable<T>
{
T Copy();
}
class DerivedClass : BaseClass, ICopyable<DerivedClass>
{
public DerivedClass Copy()
{
//do what is needed for copy and return a new DerivedClass
}
}
You can't really. The base class can't possibly know all the future implementations. You'll have to resort to a generic abstract class (like you did) type or a generic Copy method.
public abstract class CopyableClass
{
public abstract T Copy<T>() where T : CopyableClass;
}
public class DerivedClass : CopyableClass
{
public override T Copy<T>()
{
if(typeof(T) != typeof(DerivedClass))
throw new ArgumentException();
// return your copy
}
}
Or, if you want to generalize the type check in your base class:
public abstract class CopyableClass
{
public T Copy<T>() where T : CopyableClass
{
if(GetType() != typeof(T))
throw new ArgumentException();
return (T) Copy();
}
protected abstract CopyableClass Copy();
}
public class DerivedClass : CopyableClass
{
protected override CopyableClass Copy()
{
return // Your copy;
}
}
Note that the second method puts alot of trust into the implementation of the derived class as it'll blindly cast the return value of the abstracted method. The compiler will let you return another type, implementing CopyableClass, in a derived type but it will be a runtime error. This is not a problem if you have the absolute control over all of the derived implementations (ie your abstract class also have an internal constructor).
This solution involves a middle class but I think its more inline with what the you are looking for. At least you get the possible benefit of isolating your copy code
public abstract class BaseClass
{
}
public abstract class CopyableClass<T> : BaseClass
where T: BaseClass, new()
{
public T Copy()
{
var copy = new T(); // Creating a new instance as proof of concept
return copy;
}
}
public class DerivedClass : CopyableClass<DerivedClass>
{
}
You actually want to implement copy in the base class and have it return T. This will make is so you call it with a type argument and it returns that type.
public static T Copy<T>() where T : CopyableClass
{
T retVal = new T();
// do whatever copying is required
return retVal;
}
To call it you do;
DerivedClass d = Copy<DerivedClass>();
Your code to actually do the copy might be a bit more work to make generic but it's worth the effort given you will have a single implementation of Copy() that works for any derived type. I don't know what logic belongs in the method so I've just stubbed things out. Also, I'd recommend checking out generics in general. They're often the best option for things like this. If your implementations need to be unique to the base class' keep the same method definition but make it abstract and then override it in the base classes.
This will allow you to case this base class to the derived type and return it.
public abstract class BaseClass<TDerived> : where TDerived: BaseClass<TDerived>
{
public TDerived DoSomethingCommon(string param)
{
var derivedType = (TElement)this;
//do something.
return derivedType;
}
}
Is it possible to create an abstract method that must return an instance of the derived class? I can do this:
abstract class Base
{
public abstract Base GetObj();
}
class Derived : Base
{
public Derived() { }
public override Base GetObj()
{
return new Derived();
}
}
But I was wondering if there was a way to do it such that Derived::GetObj() is forced to return a Derived?
Thanks.
Using generics should make this possible:
abstract class Base<T>
where T : Base<T>
{
public abstract T GetObj();
}
class Derived : Base <Derived>
{
public Derived() { }
public override Derived GetObj()
{
return new Derived();
}
}
You could even simplify this even more (if all of the derived instances are created with default constructors):
abstract class Base<T>
where T : Base<T>, new()
{
public static T GetObj()
{
return new T();
}
}
class Derived : Base<Derived>
{
public Derived() { }
}
What you have is almost but not quite exactly an abstract factory. I will first say that you should leave it up to the implementers of the derived classes to get it right, or simply trust that they will.
Another answer has shown what is known as the curiously recurring template pattern. It is where you have a base class that tries to use the type system to enforce that derived types use itself at certain input or output positions.
public abstract class Foo<T> where T : Foo<T>
public class Bar : Foo<Bar>
This idea might work in other languages. It works in C# only so far as people use it correctly. With the above definition of Bar, now I can also have
public class Baz : Foo<Bar>
Which is perfectly legal. Bar is a Foo<Bar>, which is all that is required for Baz to use it. Nothing requires Baz to actually use Foo<Baz>.
The type system in C# simply cannot enforce what you would like enforced. Even with this pattern in place, you are still in the same position as before. You still have to trust the implementers of the derived classes to do it correctly.
For more on this topic, you might read this blog.
I have this class/interface definitions in C#
public class FooBase {
...
protected bool Bar() { ... }
...
}
public interface IBar {
bool Bar();
}
Now I want to create a class Foo1 derived from FooBase implementing IBar:
public class Foo1 : FooBase, IBar {
}
Is there some class declaration magic that the compiler takes the inherited protected method as the publicly accessible implementation of the interface?
Of course, a Foo1 method
bool IBar.Bar()
{
return base.Bar();
}
works. I'm just curious whether there is a shortcut ;)
Omitting this method results in a compiler error: Foo1 does not implement interface member IBar.Bar(). FooBase.Bar() is either static, not public, or has wrong return type.
Explanation: I separate code inheritance (class hierarchy) and feature implementation (interfaces). Thus for classes implementing the same interface, accessing shared (inherited) code is very convenient.
No shortcut. In fact, this pattern is used in a few places I've seen (not necessarily with ICollection, but you get the idea):
public class Foo : ICollection
{
protected abstract int Count
{
get;
}
int ICollection.Count
{
get
{
return Count;
}
}
}
I believe your code is as short as it can be. Don't think there is any kind of shortcut out there.
The protected member FooBase.Bar() is not an implementation method of the interface IBar. The interface demands a public Method Bar().
There are 2 ways implementing an interface. Explicit implementation or implicit implementation.
Following is explicit implementation. This method is called if an object of Foo is called through a IBar variable.
bool IBar.Bar()
{
return base.Bar();
}
Defining a public method Bar() is implicit implementation.
To have the compiler satisfied you might override or new the baseclass method as public (not a good advise, if method is protected in baseclass).
new public bool Bar()
{
return base.Bar();
}
The trick is to implement an interface, but not having all interface members as public members in the class.