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.
I don't like to answer my own question, but this one had me stumped and visually it doesn't make sense, and nobody else explained it.
After a night's sleep, it dawned on me that this is simply generic parameter shadowing. Shadowing of generic parameters apparently exists (I did not know this since I don't write inner classes much), and works just like standard parameters. So even though T is a type parameter in the outer class, the compiler treats the T in the inner method (or class) as T2, and they are not the same type, hence the error which amounts to "T is not assignable to T" because I am trying to iterate an IList with T (which should work if you look at it purely from a symbolic level). The error is:
public class MegaList<T> : ObservableCollection<T>
{
public ObservableCollection<TBase> UpCast<TBase, T>() // <-- this T isn't outer T
where TBase : class
where T : TBase
{
var listUpcast = new ObservableCollection<TBase>();
foreach (T t in this.Items) // <-- error: Argument type 'T' is not assignable to parameter type 'TBase'
listUpcast.Add(t);
return listUpcast;
}
}
And since I'd have to provide T as a generic parameter, I cannot constrain it on the inner method, which #hvd supports, so unless someone knows some syntax that I don't, I'll just give up on this and either use a cast within the method, or stick with the extension method where I can type constrain it.
I honestly cannot decide if this is a feature, or a limitation. I guess it would depend on your point of view. Hope this helps someone else. At least the C# compiler should probably improve the error message so that there is an apparent difference between types. Given that one is declared in an outer scope (so to speak) I don't see why the types should be listed as Foo.T vs Foo.T, I would think the inner T would be in the symbol namespace of the outer class, and hence have a different qualified type name like MegaList.T vs MegaList.UpCast.T.
Should not the definition of UpCast method be
public class MegaList<T> : ObservableCollection<T>
{
// ...rest of class snipped...
public ObservableCollection<TBase> UpCast<TBase>()
{
var listUpcast = new ObservableCollection<TBase>();
foreach (var t in this.Items)
listUpcast.Add((TBase)t); // <-- error: Argument type 'T' is not assignable to parameter type 'TBase'
return listUpcast;
}
}
Related
I have the following class:
public class Item<TItem>
where TItem : Item<TItem>
{
void GetReference()
{
TItem item = this;
}
}
Here TItem item = this; generates a compiler error "can't convert Item<TItem> implicitly to TItem".
But why do we need a conversion here? We have defined the constraint where TItem : Item<TItem>, so one can think that no conversion is needed at all since the two types are the same, aren't they?
Btw an explicit conversion is available. This also is stated in the compiler error.
Because it wouldn't be safe. Consider:
public class GoodItem : Item<GoodItem>
{
// No problem
}
public class EvilItem : Item<GoodItem>
{
// GetReference body would be equivalent to
// GoodItem item = this;
// ... but this *isn't* a GoodItem, it's an EvilItem!
}
EvilItem satisfies the constraint for TItem with no problems - GoodItem is indeed derived from Item<GoodItem>.
There's no way of expressing a relationship between the class being declared and a type parameter, which is what you really want.
That's because your class is type Item<TItem> not TItem. You could have;
Item<TItem> item = this;
The sample is a bit of a mind bender. To put this into context TItem item = this; resolves to trying to do
Item<TItem> item = new Item<Item<TItem>>();
because every TItem is Item<TItem> (as declared by where constraint), but not vice versa.
TItem could be more derived than Item<TItem>, so do this, TItem could be Apple and this could be oranges. so assignment is prevented by compiler.
currently in c# there is no way to declare that type parameter must match type of inheriting class itself.
there are two common ways to fix this. first use explicit cast
TItem GetReference() => (TItem) this;
Its your job to make sure inheriting class is using right type parameter, other wise you may get runtime exception if you ever try to use this method.
second way is to use return type of class itself. which is safe (no runtime exception) but does not have any sort of contract for derived classes. i.e you should make sure you write this method for every derived class.
Item<TItem> GetReference() => this;
now you can hide this method in derived classes.
new Derived GetReference() => this; // public class Derived : Item<Derived>
Note that this feature is already requested in GitHub c# repo, https://github.com/dotnet/csharplang/issues/252
you just have to wait for c# team to add this feature :)
I want something like this:
class Foo<T>{...}
class Boo<T>{
Queue<T> stuff = new Queue<T>();
public void Boo(Foo<T>){...};
}
...
//Extract the generic type - string - to define the type
//of MyBoo.
var MyBoo = new Boo(new Foo<string>());
I get the error "generic type 'Boo' requires '1' type arguments. Ya, I fixed the problem by stating the template type explicitly, but I'd like to know if there was/is a way to extract that type implicitly, rather than having to state it explicitly.
This other post may be related, but I'm not sure.
You can't do it implicitly directly with the constructor of a generic type, but you could from a generic method, e.g. in a non-generic class:
public static class Boo
{
public Boo<T> Create<T>(Foo<T> foo)
{
return new Boo<T>(foo);
}
}
Then:
// myBoo will be inferred to be of type Boo<string>
var myBoo = Boo.Create(new Foo<string>());
Of course, it doesn't have to be another class called Boo - it could be something completely different, and it could be an instance method of something else:
var factory = new BooFactory();
var myBoo = factory.Create(new Foo<string>());
The important point is that it's a generic method - type arguments can be inferred for generic methods, but not for generic types.
Type inference works only with methods. So if you have generic method and it is clear how to substitute generic parameter it will be substituted by compiler. For new operator it doesn't work so consider creating factory method like Create that will produce instances of Boo. Otherwise impossible.
I have these types:
public class GenericDao<T>
{
public T Save(T t)
{
return t;
}
}
public abstract class DomainObject {
// Some properties
protected abstract dynamic Dao { get; }
public virtual void Save() {
var dao = Dao;
dao.Save(this);
}
}
public class Attachment : DomainObject
{
protected dynamic Dao { get { return new GenericDao<Attachment>(); } }
}
Then when I run this code it fails with RuntimeBinderException: Best overloaded method match for 'GenericDAO<Attachment>.Save(Attachment)' has some invalid arguments
var obj = new Attachment() { /* set properties */ };
obj.Save();
I've verified that in DomainObject.Save() "this" is definitely Attachment, so the error doesn't really make sense. Can anyone shed some light on why the method isn't resolving?
Some more information - It succeeds if I change the contents of DomainObject.Save() to use reflection:
public virtual void Save() {
var dao = Dao;
var type = dao.GetType();
var save = ((Type)type).GetMethod("Save");
save.Invoke(dao, new []{this});
}
The problem is that some aspects of the dynamic method-call are resolved at compile-time. This is by design. From the language specification (emphasis mine):
7.2.3 Types of constituent expressions
When an operation is statically bound,
the type of a constituent expression
(e.g. a receiver, and argument, an
index or an operand) is always
considered to be the compile-time type
of that expression. When an operation
is dynamically bound, the type of a
constituent expression is determined
in different ways depending on the
compile-time type of the constituent
expression:
• A constituent expression
of compile-time type dynamic is
considered to have the type of the
actual value that the expression
evaluates to at runtime
• A
constituent expression whose
compile-time type is a type parameter
is considered to have the type which
the type parameter is bound to at
runtime
• Otherwise the constituent
expression is considered to have its
compile-time type.
Here, the constituent expression this has a compile-time type DomainObject<int> (simplification: the source-code is in a generic type, so that complicates how we should "view" the compile-time type of this, but hopefully, what I mean is understood), and since this is not of type dynamic or a type-parameter, its type is taken as its compile-time type.
So the binder looks for a method Save taking a single parameter of type DomainObject<int> (or to which it would have been legal to pass an object of type DomainObject<int> at compile-time).
It would have looked somewhat like this had the binding happened at compile-time:
// Extra casts added to highlight the error at the correct location.
// (This isn't *exactly* what happens.)
DomainObject<int> o = (DomainObject<int>) (object)this;
GenericDao<Attachment> dao = (GenericDao<Attachment>)Dao;
// Compile-time error here.
// A cast is attempted from DomainObject<int> -> Attachment.
dao.Save(o);
But this can't work since the only candidate-method of concern on GenericDao<Attachment> is Attachment Save(Attachment), and for this method, no implicit conversion exists from type of the argument (DomainObject<int>) to the type of the parameter (Attachment).
So we get the compile-time error:
The best overloaded method match for 'GenericDao<Attachment>.Save(Attachment)' has some invalid arguments
Argument 1: cannot convert from 'DomainObject<int>' to 'Attachment'
And this is the error that is deferred until run-time with the dynamic version. Reflection doesn't have the same problem because it doesn't attempt to extract "partial" information about the method-call at compile-time, unlike the dynamic version.
Fortunately, the fix is simple, defer the evaluation of the type of the constituent-expression:
dao.Save((dynamic)this);
This moves us into option 1 (compile-time type dynamic). The type of the constituent-expression is deferred until run-time, and this helps us bind to the right method. Then the statically-bound equivalent of the code is something like:
// Extra casts added to get this to compile from a generic type
Attachment o = (Attachment)(object)this;
GenericDao<Attachment> dao = (GenericDao<Attachment>)Dao;
// No problem, the Save method on GenericDao<Attachment>
// takes a single parameter of type Attachment.
dao.Save(o);
which should work fine.
Ani's answer is quite fine; Ani asked me to add some extra explanatory text at my discretion, so here you go.
Basically what's going on here is that a dynamic invocation where some of the arguments are not dynamic causes the dynamic analysis to honour the compile-time information that was known. That's maybe not clear without an example. Consider the following overloads:
static void M(Animal x, Animal y) {}
static void M(Animal x, Tiger y) {}
static void M(Giraffe x, Tiger y) {}
...
dynamic ddd = new Tiger();
Animal aaa = new Giraffe();
M(aaa, ddd);
What happens? We have to do a dynamic invocation, so the runtime type of ddd is used to do overload resolution. But aaa is not dynamic, so its compile time type is used to do overload resolution. At runtime the analyzer tries to solve this problem:
M((Animal)aaa, (Tiger)ddd);
and chooses the second overload. It does not say "well, at runtime aaa is Giraffe, therefore I should be solving the problem:
M((Giraffe)aaa, (Tiger)ddd);
and choose the third overload.
The same thing is happening here. When you say
dao.Save(this)
the compile-time type of dao is "dynamic", but the compile-time type of "this" is not. Therefore when solving the overload resolution problem at runtime, we use the runtime type of "dao" but the compile-time type of the argument. The compiler would have given an error for that combination of types, and therefore so does the runtime binder. Remember, the runtime binder's job is to tell you what would the compiler have said if it had all the information available about everything that was marked 'dynamic'. The runtime binder's job is not to change the semantics of C# to make C# a dynamically typed language.
Quite good answers here already. I ran into the same problem. You're right reflection does work. Because you are specifying the type by saying GetType() which gets resolved at runtime.
var method = ((object)this).GetType().GetMethod("Apply", new Type[] { #event.GetType() }); //Find the right method
method.Invoke(this, new object[] { #event }); //invoke with the event as argument
Or we can use dynamics as follows
dynamic d = this;
dynamic e = #event;
d.Apply(e);
So in your case
public abstract class DomainObject {
// Some properties
protected abstract dynamic Dao { get; }
public virtual void Save() {
var dao = Dao;
dynamic d = this; //Forces type for Save() to be resolved at runtime
dao.Save(d);
}
}
This should work.
The code is confusing. I see two possible options here.
Dao is actually the parent of GenericDao because otherwise your getter has type mismatch:
public class Dao
{
void Save();
}
public class GenericDao<T> : Dao
{
public virtual T Save(T) {...}
}
// error here because GenericDao does not implement Dao.
protected dynamic Dao { get { return new GenericDAO<Attachment>(); } }
Alternatively, Dao may be a child of GenericDAO. But in this case the getter is not correct either and the situation is actually worse.
So the bottom line is that there is a problem with your class/interface hierarchy. Please clarify and I will update my answer accordingly.
(Thanks everyone for the answers, here is my refactored example, in turn another StackOverflow question about the Single Responsibility Principle.)
Coming from PHP to C#, this syntax was intimidating:
container.RegisterType<Customer>("customer1");
until I realized it expresses the same thing as:
container.RegisterType(typeof(Customer), "customer1");
as I demonstrate in the code below.
So is there some reason why generics is used here (e.g. throughout Unity and most C# IoC containers) other than it just being a cleaner syntax, i.e. you don't need the typeof() when sending the type?
using System;
namespace TestGenericParameter
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
container.RegisterType<Customer>("test");
container.RegisterType(typeof(Customer), "test");
Console.ReadLine();
}
}
public class Container
{
public void RegisterType<T>(string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name);
}
public void RegisterType(Type T, string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name);
}
}
public class Customer {}
}
//OUTPUT:
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
One reason when generics are very useful is when the generic type parameter is used as the type of a parameter or as the return type of the method.
That means, you can write methods like
public T GetAs<T>(string name)
where the return type can be checked by the compiler and boxing value types can sometimes be avoided.
The caller would write:
int value = GetAs<int>("foo");
Whithout generics, you would have to write
public object GetAs(Type t, string name)
and the caller has to cast the result again:
int value = (int)GetAs(typeof(int), "foo");
A primary reason is the type safety at compile time. If you are passing two Type objects you are placing the responsibility at the developer instead of the compiler.
This is also why many IoC containers utilizes it, as your compiler will complain if an concrete type isn't inheriting the abstract type.
public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract
{
}
This code will only work if TConcrete is implementing or inheriting TAbstract. If this method took two Type parameters, your method should validate this relationship.
A simple answer is type inference where possible.
If the generic type is used in the method signature, you can omit it because the type could be inferred:
void SomeMethod<T>(T x, T y) where T : IComparable<T> {
Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y));
}
So the usage is simplified:
SomeMethod(3, 4); // instead of SomeMethod<int>(3, 4);
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two");
If the generic type parameter is not used in the method signature the type inference is not possible:
var emptySequence = Enumerable.Empty<int>();
I think one of the primary uses is type safety with arguments and return values. In your example case, there is not much use for generics, because the input/output types (string) do not match the generic case (customers).
A more appropriate use might be:
public T RegisterType<T>(string name)
{
T obj = new T();
obj.DoSomething();
return obj;
}
or maybe
public void DoSomething<T>(T obj)
{
//operate on obj
}
If you didn't use Generics, you'd either have to overload a method for each type you want to support, or you'd have to accept the parameter as an object and perform casting logic.
For one example, compare the code needed to create an instance of your type using the typeof option versus a generic. Or return an instance of the type. Or accept an instance of the type as an argument. Or set a property on an instance of the type.
In general, if you will be working only with the type itself you can accept a type parameter. If you want to do anything with an instance of the type, use a generic.
Another reason to use a generic is if you want to apply constraints to the type. For example, you can require the type to implement one or several interfaces, inherit another type, be a reference type or value type, have a default constructor, or some combination of the above. The compiler will enforce this so you can't build code that doesn't comply with your requirements.
I'd say the best reason is type safety, using the "where" keyword, to ensure that the generic type is of a certain type (or sub-class/implementor). Using "typeof" will let you send anything through.
public void Getrecords(ref IList iList,T dataItem)
{
iList = Populate.GetList<dataItem>() // GetListis defined as GetList<T>
}
dataItem can be my order object or user object which will be decided at run time.The above does not work as it gives me this error
The type 'T' must have a public parameterless constructor in order to use it as parameter 'T' in the generic type
public void GetRecords<T>(ref IList<T> iList, T dataitem)
{
}
What more are you looking for?
To Revised question:
iList = Populate.GetList<dataItem>()
"dataitem" is a variable. You want to specify a type there:
iList = Populate.GetList<T>()
The type 'T' must have a public
parameterless constructor in order to
use it as parameter 'T' in the generic
type GetList:new()
This is saying that when you defined Populate.GetList(), you declared it like this:
IList<T> GetList<T>() where T: new()
{...}
That tells the compiler that GetList can only use types that have a public parameterless constructor. You use T to create a GetList method in GetRecords (T refers to different types here), you have to put the same limitation on it:
public void GetRecords<T>(ref IList<T> iList, T dataitem) where T: new()
{
iList = Populate.GetList<T>();
}
Your revised question passes in dataItem as an object of type T and then tries to use it as a type argument to GetList(). Perhaps you pass dataItem in only as a way to specify T?
If so, the you may want something like so:
public IList<T> GetRecords<T>() {
return Populate.GetList<T>();
}
Then you call that like so:
IList<int> result = GetRecords<int>();
The issue with demanding a public, parameterless constructor can only be because Populate.GetList demands it - i.e. has the "T : new()" constraint. To fix this, simply add the same constraint to your method.
Actually, I doubt that ref is a good strategy here. At a push, out might do (since you don't read the value), but a far simpler (and more expected) option is a return value:
public IList<T> GetRecords<T>(T dataItem) where T : new()
{ // MG: what does dataItem do here???
return Populate.GetList<T>();
}
Of course, at that point, the caller might as well just call Populate.GetList directly!
I suspect you can remove dataItem too... but it isn't entirely clear from the question.
If you don't intend it to be generic (and dataItem is the template object), then you can do this via MakeGenericMethod:
public static IList GetRecords(object dataItem)
{
Type type = dataItem.GetType();
return (IList) typeof(Populate).GetMethod("GetList")
.MakeGenericMethod(type).Invoke(null,null);
}
You can use Generic with < T > that will accept the type in runtime like you want.
Getrecords<T> ...
This should have any more detailed information that you need.
http://msdn.microsoft.com/en-us/library/twcad0zb(VS.80).aspx