The code below doesnt compile (Error 1 Cannot implicitly convert type 'A' to 'BaseString<T>')
Although the idea is simple but it doesnt work with generic type.
What is the "proper" way to implement that Thank you!
class Base<T1, T2>{ }
class BaseString<T>: Base<T, string>{ }
class A : BaseString<Int16>{ }
class B : BaseString<Int32>{ }
class Main<T>
{
BaseString<T> var;
void Method()
{
if (var is Int16)
var = new A();
else|
var = new B();
}
}

Simple question abt inheritance tree and generic type
shinji360
C# uses static type checking - it performs checks at compile time. It does not do any flow analysis to make these checks. So when you perform an assignment statement, it will only look at the assignment - it won't perform any broader analysis. So it's just looking at this line of code:
Given that this is the only context, the compiler is correctly telling you that the conversion you're trying to perform is not always going to succeed, so you can't just use an assignment like that.
For example suppose I decide to do this:
The type of the var field in this case will be BaseString<string>. The type of A is BaseString<Int16>. These two types are incompatible.
As it happens, that line of code will never execute. The type of var will never be Int16, it will always be BaseString<something>. This means that the if statement will always follow the second branch. This means you will always execute this:
This suffers from the same problem - suppose we have the instantiation of Main<string> - var will be of type BaseString<string> but B is derived from BaseString<Int32>
You can try and force the issue, e.g.:
That will compile, but it will fail at runtime, because you are performing an invalid cast.
In short, the code you've written is trying to perform an illegal cast, and the C# compiler has correctly told you that this is the case.
Roygana
Thanx for your time Ian. But the question was - how to properly hit the target (not why the error happened).
I need advice of how to implement simple OOA pattern in C# 2.0
Basically it is simple subclassing. When I have similar but not the same implementation for different types. Where the Main class can use variable of Base class (or to be precise - of both types A and B - depends of what type it was initialised).
I can do similar thing when no generic type there.
Base var; var = new A(); /* valid */ var = new B(); /* valid */
Thank you anyway.
talon121
Looking at your post, your original question was actually "What is the "proper" way to implement that " and you didn't specify what "that" was. So I apologise for not answering the question you had in mind, but it wasn't really clear what you meant.
Now that you've clarified the question, I think I see where you're coming from.
You appear to have missed a fundamental point about generics. When you say "it's simple subclassing" actually it isn't. You're asking for something different, and which wouldn't actually make sense in the general case.
By removing the generics, you've ended up with just one class called Base:
But in your original, you had this:
This generic class was able to create many unrelated classes. So Base<int, double> is a completely different class from Base<short, float>, which is a completely different class from Base<bool, string> etc.
So the only inheritance relationship between instantiations of Base is that they all derive from System.Object.
Let's look at your original A and B. Here are their respective inheritance chains:
A : BaseString<Int16> : Base<Int16, string> : System.Object
B : BaseString<Int32> : Base<Int32, string> : System.Object
Note that the only base class that these two have in common is System.Object.
If you think that these two share the base class Base or BaseString, then that's the heart of how you've misunderstood generics. BaseString<Int16> is a completely different class from BaseString<Int32>. There is no type compatibility relationship there because they are different classes.
Now let's look at your new code. Here are the inheritance chains of A and B with the generics removed:
A : BaseString : Base : System.Object
B : BaseString : Base : System.Object
Now the two types have the same base class. So both A and B are type compatible with BaseString, Base, and System.Object. This is why your assignment succeeds in the second case - it's because this time, A and B share a common base class. (Other than System.Object.)
If you wanted to make non-generic versions of A and B that were truly equivalent to your generic version, this would be a better approximation:
That comes closer to how the CLR and C# view your generic code. A and B both derive from different unrelated base classes. The fact that both are called BaseString in the generic example isn't relevant: they have different template parameters, so they are considered to be different clases. (And I hope it's clear in this case that you wouldn't be able to assign both an A and a B into the same variable unless that variable was of type System.Object.)
If you're wondering why BaseString<Int16> is considered a completely different class from BaseString<Int32>, it helps to look at a slightly more complete example. Your BaseString and Base classes are both completely empty, which makes it hard to see why the CLR treats them as different classes. If you put something in them it becomes easier to understand.
Consider this:
Now suppose we have some method that uses a specific instantiation of this class:
Now suppose what you're asking for were true. You appear to be asking for any Base<T1, T2> to be type compatible with any other Base<T1, T2>. If that were true I'd be able to do this:
But this would make no sense. When UseBase calls Foo, it passes in an Int32 and a String, but the Base<T1, T2> passed in here is expecting a bool and a float. Likewise, when UseBase retrieves member1 and member2, it expects them to be of type Int32 and String, but they're actually of type bool and float.
In general, you cannot expect one instantiation of a generic type to be compatible with another instantiation of a generic type. For any non-trivial case, such as the example I've shown here, two different instantiations of the same generic class are likely to be different, and so it would make no sense for the type system to treat them as equivalent.
And because of that, it makes no sense for the type system to treat classes derived from two different instantiations of some Base<T1, T2> as being equivalent.
In the very simple sample code you posted here, there's a structural equivalence. Because your Base<T1, T2> and BaseString<T> classes contained no implementation, there was no obvious difference between them. Their structural equivalence was an upshot of the fact that they are empty classes.
But C# does not use structural typing. Nor does the CLR. The fact that two classes have identical structure does not make them the same class. Some languages use structural equivalence rules to determine type compatibility, but C# does not.