I renamed the question from: "Why does my UpCast() not compile as an instance method but does as an extension?" to something a bit more useful for the future emaciated adventurer.
I originally set out to implement an UpCast() as an instance method, but eventually ended up boggling over a compiler message that didn't seem to make sense. The original question is below, with the update.
I have a container class derived from ObservableCollection. Just now I tried to write an UpCast<> generic method so that instead of writing:
Columns = new MegaList<DbTableColumn>();
Columns.AddRange( oracleDictionary.ListTableColumns(tableName) ); // IEnumerable<OracleColumn>
// or
(v.Columns = new MegaList<DbTableColumn>()).AddRange( oracleDictionary.ListTableColumns(tableName) );
// I could instead write
Columns = oracleDictionary.ListTableColumns(tableName).UpCast<DbTableColumn>();
MegaList is ObservableCollection with some added convenience methods that I won't show here. Since ObservableCollection does not have ConvertAll(), I tried this.
Basically, why doesn't the following instance method compile, yet I can implement the seemingly equivalent as an extension method (listed at the bottom), it does?
public class MegaList<T> : ObservableCollection<T>
{
// ...rest of class snipped...
public ObservableCollection<TBase> UpCast<TBase, T>()
where TBase: class
where T : TBase
{
var listUpcast = new ObservableCollection<TBase>();
foreach (T t in this.Items) <-- Error 14 Cannot convert type 'T' to 'T' ??? Excuse me?
listUpcast.Add(t);
return listUpcast;
}
}
I think the following is equivalent. Just exchanges the "this" parameter for the OberservableCollection.Items property, both hold type T. I am especially confused because of the type constraint that states "T must be TBase".
static public ObservableCollection<TBase> UpCast<TBase, T>(this ObservableCollection<T> list)
where TBase : class
where T : TBase
{
var listUpcast = new ObservableCollection<TBase>();
foreach (var t in list)
listUpcast.Add(t);
return listUpcast;
}
UPDATE: The answer is below, and I found the following to be true:
- C# has generic type parameter shadowing, just like regular field/parameter shadowing.
- I can't write a type constraint in a generic method using a type parameter from the enclosing class, because of (1) and I don't think there is a way to refer to type within a type constraint, where T is a generic type parameter.