Generics cannot cast a T : class to Object

K

kasper.rung

I am having trouble implementing an interface. The interface requires
a method to return an object, but it does not seem to be able to treat
a reference type as an object. I have the following sample code:

using System;
using System.Collections.Generic;
using System.Text;

namespace GenericsTest
{
public interface IMyClass
{
object Foo();
}

public class MyClass<T> : IMyClass where T : class
{
public T Foo()
{
// Foo
}
}
}

Howcome the public T Foo() is not returning an object even when T is
constrained to be only of reference type? Doesn't that automatically
ensure we are dealing with objects?

Thank you, Kasper
 
R

rossum

I am having trouble implementing an interface. The interface requires
a method to return an object, but it does not seem to be able to treat
a reference type as an object. I have the following sample code:

using System;
using System.Collections.Generic;
using System.Text;

namespace GenericsTest
{
public interface IMyClass
{
object Foo();
}

public class MyClass<T> : IMyClass where T : class
{
public T Foo()
{
// Foo
}
}
}
Because you specify the return type as T the compiler thinks that this
foo() is not the implementation of IMyClass.foo(), because the return
types do not match.

Your foo() here does not return anything. You need to return
something from your foo() as there is no conversion from nothing to
Object.


Try:

public class MyClass<T> : IMyClass where T : new() // no "class"
{
public object Foo()
{
// Foo
return new T();
}
}

Your class constraint is not needed as value types can be boxed to
make them into objects.

Howcome the public T Foo() is not returning an object even when T is
constrained to be only of reference type? Doesn't that automatically
ensure we are dealing with objects?
The code of foo() can return anything as anything is convertible to
Object. The declared return type has to match the declared return
type of the interface you are implementing.
 
J

Jon Skeet [C# MVP]

I am having trouble implementing an interface. The interface requires
a method to return an object, but it does not seem to be able to treat
a reference type as an object.

This has nothing to do with generics. It's the same reason that when
you implement ICloneable, you have to declare that Clone() returns
object, not your type - .NET doesn't have covariant return types for
interface implementation or method overriding.
 
K

kasper.rung

Thank you for the answers.

Rossum, i realize that the code would not compile with out the return,
but unfortuantely that does not change the problem.

My question should have been:

Why does MyClass<T>.Foo not match IMyClass.Foo? As we have all pointed
out a T, an int or any value or any object can be cast to an object.

I think the problem is this lack of covariant return types. What is
that about? Is the compiler not capable of realizing that
MyClass<T>.Foo returns an object, and that it therefore could be used
as an implementation of IMyClass.Foo?

- Kasper
 
J

Jon Skeet [C# MVP]

Thank you for the answers.

Rossum, i realize that the code would not compile with out the return,
but unfortuantely that does not change the problem.

My question should have been:

Why does MyClass<T>.Foo not match IMyClass.Foo? As we have all pointed
out a T, an int or any value or any object can be cast to an object.

Yes, it can be cast to an object, but to implement an interface the
return type has to match exactly.
I think the problem is this lack of covariant return types. What is
that about? Is the compiler not capable of realizing that
MyClass<T>.Foo returns an object, and that it therefore could be used
as an implementation of IMyClass.Foo?

I believe it's not that the compiler doesn't realise it, it's that .NET
itself doesn't support covariant return types. Yes, it's a pain, but
that's the way it is.
 
P

PS

I am having trouble implementing an interface. The interface requires
a method to return an object, but it does not seem to be able to treat
a reference type as an object. I have the following sample code:

using System;
using System.Collections.Generic;
using System.Text;

namespace GenericsTest
{
public interface IMyClass
{
object Foo();
}

public class MyClass<T> : IMyClass where T : class
{
public T Foo()
{
// Foo
}
}
}

Howcome the public T Foo() is not returning an object even when T is
constrained to be only of reference type? Doesn't that automatically
ensure we are dealing with objects?

The interface needs to know about the type T. Why not declare your interface
like:

public interface IMyClass<T>
{
T Foo();
}

public class MyClass<T> : IMyClass<T> where T : class
{
public T Foo()
{
return default(T);
}
}
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Thank you for the answers.

Rossum, i realize that the code would not compile with out the return,
but unfortuantely that does not change the problem.

My question should have been:

Why does MyClass<T>.Foo not match IMyClass.Foo? As we have all pointed
out a T, an int or any value or any object can be cast to an object.

I think the problem is this lack of covariant return types. What is
that about? Is the compiler not capable of realizing that
MyClass<T>.Foo returns an object, and that it therefore could be used
as an implementation of IMyClass.Foo?

- Kasper

If the implementation of an interface would allow inherited types for
return values, that would mean that it limits the use of the interface
when you inherit the class.

The subclass can not override the method and implement it with the
return type specified in the interface, it still has to return the same
datatype as your class.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top