This question already has answers here:
Cast from Generics<T> to Specific SubClass
(9 answers)
Closed 7 years ago.
I have a simple interface and two classes implement it:
public interface IMovable { }
public class Human : IMovable { }
public class Animal : IMovable { }
The following generic method results in a compile-time error: Cannot convert type 'Human' to 'T'
public static T DoSomething<T>(string typeCode) where T : class, IMovable
{
if (typeCode == "HUM")
{
return (T)new Human(); // Explicit cast
}
else if (typeCode == "ANI")
{
return (T)new Animal(); // Explicit cast
}
else
{
return null;
}
}
But when the as keyword is used, all is fine:
public static T DoSomething<T>(string typeCode) where T : class, IMovable
{
if (typeCode == "HUM")
{
return new Human() as T; // 'as'
}
else if (typeCode == "ANI")
{
return new Animal() as T; // 'as'
}
else
{
return null;
}
}
Why does as work but explicit cast doesn't?
Short answer is, because T doesn't have to be of the correct type. Compiler is really trying to help you here, because you are doing something which might easily fail in runtime.
E.g. consider what happens with:
var result = DoSomething<Human>("ANI");
Longer answer is, you shouldn't be casting at all. Casting indicates problems with your OOP design, and is especially wrong when using generics: you lose the whole point of generics, actually. Generics are supposed to allow you create a "template" which abstracts away the actual type, leaving you to worry about the algorithm itself instead of concrete types.
In this case, you probably don't need generics at all. Your method is basically a less safer way of doing this:
public static T DoSomething<T>() where T : new()
{
return new T();
}
or this:
public static IMovable DoSomething(string typeCode)
{
if (typeCode == "HUM")
return new Human();
if (typeCode == "ANI")
return new Animal();
return null;
}
To silence the compiler, you may also add an intermediate cast, which tells the compiler you went an extra step to indicate that you really want to cast it this way: For example, using
(T)(object)new Human()
or
(T)(IMovable)new Human()
will both pass compilation, although the conversion from IMovable to T is no safer than the original code, and casting an object to T even unsafer. But this is not the solution to your underlying issue, which is design related.
With your code, it is perfectly possible to call DoSomething<Animal>, and then you have (Animal)new Human().
That is biologically correct, but your model does not allow it.
Do you really need generics here? Maybe you just want to return IMovable in this case.
Under the covers, the 'as' will do an 'is' check first before attempting the cast. So it will not attempt it if it can't cast it and will then return null.
Related
Suppose we have an interface with a single generic method:
public interface IExtender
{
T GetValue<T>(string tag);
}
and a simple implementation A of it that returns instances of two different types (B and C) depending on the "tag" parameter:
public class A : IExtender
{
public T GetValue<T>(string tag)
{
if (typeof(T) == typeof(B) && tag == null)
return (T)(object) new B();
if (typeof(T) == typeof(C) && tag == "foo")
return (T)(object) new C();
return default(T);
}
}
is it possible to avoid the double cast (T)(object)? Or, is there a way to tell the compiler "hey, I am sure that this cast won't fail at runtime, just let me do it without first casting to object!"
Or, is there a way to tell the compiler "hey, I am sure that this cast won't fail at runtime, just let me do it without first casting to object!"
No, the language is deliberately designed to prevent this. Eric Lippert blogged about this recently. I agree it's annoying, but it does make a certain kind of sense.
To be honest, "generic" methods like this are usually a bit of a design smell. If a method has to have special cases for various different types, you should at least consider using separate methods instead. (GetB, GetC)
public T MyMethod<T>(string tag) where T : class
{
return new A() as T;
}
check this sample:
public T GetValue<T>(string tag) where T : class, new()
{
if (typeof(T) == typeof(B) && tag == null)
return new T();
if (typeof(T) == typeof(C) && tag == "foo")
return new T();
return default(T);
}
no cast needed, you can create instance of "T", just add the generic constraint that saying that T is a class and it have parameterless constructor so you don't need to create another base types and you can be sure that only suitable types will go through this generic method.
You can use dynamic to store your real result, but you have to be sure the generic argument type is the right type you return.
TResult GetResult<TResult>()
{
dynamic r = 10;
return r;
}
No, that is not possible. The only way to do so would be to let the compiler know about additional assumptions on T. As evidenced by the list of generic parameter constraints, there is no constraint defined in C# to require availability of a specific cast.
if you let B and C implement the same interface you could use a type constraint on your T. Probably not exactly what you want, but as suggested also by others what you want is not really possible.
public interface IclassBndC {}
public class B : IclassBandC {}
public class C : IclassBandC {}
public class A : IExtender
{
public T GetValue<T>(string tag) where T : IclassBandC
{
if (tag == null)
return new B();
if (tag == "foo")
return new C();
return default(T);
}
}
There is a tool I'm modifying as I want to be able to use a generic type.
It has properties "AsDouble", "AsBool", etc.
I want to force a typecast and I don't care if it throws in runtime. I just want it to compile.
So... this does not compile...
public T As<T>()
{
Type type = typeof(T);
if (type == typeof(Double))
{
return (T)(AsDouble);
}
// more conditionals
}
Yet this does...
public T As<T>()
{
Type type = typeof(T);
if (type == typeof(Double))
{
return (T)(AsDouble as object);
}
// more conditionals
}
Why is it acting like this? How do I make it stop complaining and just do what I ask it too? Or is there a much better way of doing this than what I have in mind?
// Not duplicate of the one suggested. (Type1)Type2 does not work... I am wondering why converting from T1 to T2 to T3 works but not T1 to T3. (T1 being double, T2 being object, T3 being generic type.) Please read my question before flagging it as a duplicate.
If T does not have any type constraints the compiler will not know what type of casting to do as the relation between T and double is not known. The only way I know to achieve what you want is to cast through object, which might generate a box/unbox operation (it might get optimized but I am not sure).
In the case of generic methods with clear specializations by type I have employed the following pattern:
class Owner
{
class AsHelper<T>
{
public static Func<Owner, T> As;
}
static Owner()
{
AsHelper<double>.As = _ => _.AsDouble;
// Other implementations
}
public T As<T>() where T: struct
{
if(AsHelper<T>.As != null)
{
return AsHelper<T>.As(this);
}
else
{
// Default implementation or exception
return default(T);
}
}
}
This keeps the specializations in their own methods. From my performance testing it does about the same as the if base approach. Since statics are per generic class instantiation in .NET not per generic class definition the As field of AsHelper<T> will have a different value for each T
I'm trying to get a generic interface with implentation for handling my xml:
IXmlService
List<T> Load<T>() where T : class;
XmlService
public List<T> Load<T>() where T : class {
Type type = typeof(T);
if (type == typeof(TicketData)) { return XmlTicketService.LoadInternal(); } // Error: Unable to cast from List<TicketData> to List<T>
And the XmlTicketService.LoadInternal() knows the type and should return to Service
internal static List<TicketData> LoadInternal() {
List<TicketData> result = new List<TicketData>();
ThreadPool.QueueUserWorkItem(
delegate {
try {
XDocument data = XDocument.Load(_xmlPath);
var query = (from element in data.Root.Descendants("Ticket")
select new TicketData() {
Hope u have and advices for me :)
Well, in this case you can just cast, going via object:
if (typeof(T) == typeof(TicketData))
{
return (List<T>) (object) XmlTicketService.LoadInternal();
}
The object cast first basically forces the compiler to treat it as a "normal" cast.
... but personally I think that raises a design smell, where you should probably be creating a generic interface with a non-generic method, and implementing ILoadable<TicketData> or whatever. Basically your method isn't really generic - it has specific handling for specific types, which should always make you question whether your design is really appropriate.
Why does the following compile?
public IList<T> Deserialize<T>(string xml)
{
if (typeof(T) == typeof(bool))
return (IList<T>)DeserializeBools(xml);
return null;
}
private static IList<bool> DeserializeBool(string xml) { ... do stuff ... }
But this doesn't
public MyClass<T> GetFromDb<T>(string id)
{
if (typeof(T) == typeof(bool))
return (MyClass<T>)GetBoolValue(id); <-- compiler error here
return null;
}
private static MyClass<bool> GetBoolValue(string id) { ... do stuff ... }
The reason interfaces work is that any object might implement IList<T> (unless it's known to be an instance of a sealed type which doesn't implement it, I guess) - so there's always a possible reference type conversion to the interface.
In the latter case, the compiler isn't willing to do that because it doesn't really know that T is bool, despite the previous if statement, so it doesn't know what conversion to try between MyClass<T> and MyClass<bool>. The valid conversions to generic types are pretty limited, unfortunately.
You can fix it fairly easily:
return (MyClass<T>)(object) GetBoolValue(id);
It's ugly, but it should work... and at least in this case it won't be causing any boxing.
C# 4.0 allows declaration of covariance and contravariance on parameterized interface and delegate types.
What happens if you replace
return (MyClass<T>)
with
return (MyClass<bool>)
How to write a generic method in Java.
In C# I would do this
public static T Resolve<T>()
{
return (T) new object();
}
Whats the equivalent in Java?
First, your C# example is wrong; it will throw an InvalidCastException unless typeof(T) == typeof(object). You can fix it by adding a constraint:
public static T Resolve<T>() where T : new() {
return new T();
}
Now, this would be the equivalent syntax in Java (or, at least, as close as we can get):
public static <T> T Resolve() {
return (T) new T();
}
Notice the double mention of T in the declaration: one is the T in <T> which parameterizes the method, and the second is the return type T.
Unfortunately, the above does not work in Java. Because of the way that Java generics are implemented runtime type information about T is not available and so the above gives a compile-time error. Now, you can work around this constraint like so:
public static <T> T Resolve(Class<T> c) {
return c.newInstance();
}
Note the need to pass in T.class. This is known as a runtime type token. It is the idiomatic way of handling this situation.
As other commenters have pointed out, you can do this with Java as well - with as much of a possibility to create a casting exception at runtime:
#SuppressWarnings("unchecked")
public static <T> T resolve() {
return (T) new Object();
}
Unless you use the #SuppressWarnings annotation, however, Java's type erasure comes into play and you will get a compiler warning. The exception will also occur somewhere else: whereever you are trying to use it:
String s = <String>resolve();
will throw the exception.
On the other hand, you probably wanted to use new T() in C# anyway. This you cannot do in Java. The suggested workaround is to use Class<T> as a type parameter if you need to rely on type information at runtime. For your example, this would mean that you have to refactor it to this version:
public static <T> T resolve(Class<T> type) {
try {
return type.newInstance();
} catch(Exception e) {
// deal with the exceptions that can happen if
// the type doesn't have a public default constructor
// (something you could write as where T : new() in C#)
}
}
By the way, you can use this also to get rid of the warning in the previous case and to place the runtime exception at a more sensible line:
public static <T> T resolve(Class<T> type) {
return type.cast(new Object());
}
This piece of code will behave exactly like the one you gave as an example - including an exception that occurs when T is any type different from Object.
Try this http://java.sun.com/docs/books/tutorial/extra/generics/methods.html
public static <T> T Resolve()
{
return (T) new Object();
}
Be careful about (T) but I am not sure that this is correct. I know that generic cast causes a lot of problems. I have already spent with it a lot of time...
You want some kind of factory:
public interface MyFactory<T> {
T newInstance();
}
Then that can be passed into where it is needed. In your code:
public static T resolve<T>(MyFactory<T> factory) {
return factory.newInstance();
}
Note: There is absolutely no reason to be using reflection for this!!