2

Could you help me to understand the error in those case ?

public interface IGeneralInterface
{
}


public class A : IGeneralInterface
{
}

public class B : IGeneralInterface
{
}

public class SomeClass<TGenericType> where TGenericType : IGeneralInterface
{
    private TGenericType internalValue;

    public SomeClass(TGenericType InitValue)
    {
        internalValue = InitValue;
    }

    public TGenericType CreateAnother()
    {
       TGenericType val1 = new B();   //Error here: class B() could not be converted to TGenericType
       return val1;
    }
}

Even if I build the SomeClass<T> as

SomeClass<IGeneralInterface> someClass = new SomeClass<IGeneralInterface>();

I explicity pass base interface to include all (?) cases and it still throw an error

Tilak
  • 30,108
  • 19
  • 83
  • 131
Alex F
  • 3,180
  • 2
  • 28
  • 40

3 Answers3

3

Change

 TGenericType val1 = new B();   //Error here: class B() could not be converted to TGenericType

To

  IGeneralInterface val1 = new B();   

You are trying to TypeCast IGeneralInterface to TGenericType which is the cause of error.

TGenericType could have other constraints, like it inherits from ISpecificInterface from which B donot inherit. In this case the assignment becomes invalid.

Example:

public class SomeClass< TGenericType> where TGenericType : IGeneralInterface, ISpecificInterface
TGenericType val1 = new B(); // TGenericType should be ISpecificInterface also, B is not.

For above to run. IGenericInterface should always be more specific than TGenericType.

 public class SomeClass <IGenericInterface> 

Alternatively you could use is keyword to find out whether the object is assignable to TGenericType and then use the casting.

TGenericType val1 = default(TGenericType);
var val = new B();
if ( val is TGenericType)
{
  val1 = (TGenericType)val;
}

EDIT For the below comment

how it could at runtime have additional requirements ? Everything I put in compiler listed here

CreateAnother() creates instance of Type B which is not generic. Take below example

SomeClass<C> c = new SomeClass<C();
C another = c.CreateAnother(); // C is not assignable from B. (C is below). But It would be valid, if compiler did not flag the error

public class C : IGeneralInterface, IDisposable
{
}
Tilak
  • 30,108
  • 19
  • 83
  • 131
  • You are trying to TypeCast IGeneralInterface to TGenericType which is the cause of error. <-- yes. Why does it happens ? I explicity send IGeneralInterface as type for TGenericType – Alex F Jan 01 '13 at 12:30
  • 1
    But `TGenericType` could also extend other interface, which `IGenericInterface` does not have – Tilak Jan 01 '13 at 12:38
  • @Jasper: No you did not. You merely required that TGenericType implements the IGeneralInterface. Since the TGenericType used at run-time may have additional requirements, your class has no way to know how to convert `B` into whatever type TGenericType may be invoked as. – RBarryYoung Jan 01 '13 at 12:38
  • @Tilak: You the first to answer - so thank you, but please try to stay in condition listed above. I do not add any another condition. Inheritance stay as they listed. Please do not add more conditions. – Alex F Jan 01 '13 at 12:59
  • @RBarryYoung - how it could at runtime have additional requirements ? Everything I put in compiler listed here. – Alex F Jan 01 '13 at 13:02
  • @Tilak Thank you for your time. I Found the answer here: http://stackoverflow.com/questions/9501439/generics-in-c-sharp-cannot-convert-classname-to-tgenericclass (so the JeppeStigNilsen was the closes one) but you are the first to answer me. Thank you ! – Alex F Jan 01 '13 at 13:11
1

Why do you think a new B() should be convertible to TGenericType? The only thing that is known about TGenericType is that it implements the interface.

As an example, new B() cannot be converted to type A.

I don't know what you are trying to obtain, but you could change the generic constraint to:

public class SomeClass<TGenericType>
    where TGenericType : class, IGeneralInterface, new()

Then it would be OK to say new TGenericType() inside your create method.

But the it would no longer be possible to use the type SomeClass<IGeneralInterface> because that interface does not have an accessible parameterless instance constructor (no interface can have constructors, of course).

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • As an example, new B() cannot be converted to type A. <-- it could via the interface that they both inherited from. Or at least they could be converted to base interface. And the base interface **it is** a type for generic class (TGenericType) – Alex F Jan 01 '13 at 13:05
  • 1
    @Jasper It sounds like you're turning things the wrong way round. So-called transitivity means that if X converts to Y, and Y converts to Z, then X converts to Z. But you can't reverse the direction. You have: **`TGenericType` converts to `IGeneralInterface`** and **`B` converts to `IGeneralInterface`**. But both conversions go **towards** `IGeneralInterface`. So you can't use transitivity to conclude anything about `B` and `TGenericType` being interconvertible. – Jeppe Stig Nielsen Jan 01 '13 at 13:17
  • Thank you ! This was the part that I was missing. Thank you ! (Sorry - I already gave an 'answer' to Tilak because he/she was first) – Alex F Jan 01 '13 at 13:32
  • (@Jasper It _is_ possible to change one's mind regarding which answer one marks as "accepted", so you could change it if you want, but it's also fine to reward quick answers.) – Jeppe Stig Nielsen Jan 01 '13 at 14:49
  • :) Tilko gave me a technical solution that is correct but you really understand the defect in my logic/thinking. Thank you ! – Alex F Jan 01 '13 at 15:39
0

The problem in your code is that you are declaring the variable

val1 

of the type

TGenericType

and then you try to instantiate it by an object of a different type.

Even if you have stated the condition that the generic type of your class must be in the inheritance hierarchy of IGeneralInterface they are different for the compiler. I assume in this setting you would have to use an explicit cast.

marc wellman
  • 5,808
  • 5
  • 32
  • 59