Cast Object to Generic Type for Returning

Cast Object to Generic Type for returning

You have to use a Class instance because of the generic type erasure during compilation.

public static <T> T convertInstanceOfObject(Object o, Class<T> clazz) {
try {
return clazz.cast(o);
} catch(ClassCastException e) {
return null;
}
}

The declaration of that method is:

public T cast(Object o)

This can also be used for array types. It would look like this:

final Class<int[]> intArrayType = int[].class;
final Object someObject = new int[]{1,2,3};
final int[] instance = convertInstanceOfObject(someObject, intArrayType);

Note that when someObject is passed to convertToInstanceOfObject it has the compile time type Object.

How does casting this object to a generic type work?

Generics don't exist at runtime. At runtime, every UnaryOperator<T> is a UnaryOperator<Object>. The cast is necessary to placate the compiler at compile-time. At runtime it's meaningless.

How to cast object to generic class without knowing T

You can use System.Linq.Expressions to construct a "trampoline" - a call into a method which is generic. Once you're inside that generic method, then you can start using T naturally when you need to talk about the type. Here I'm using BuildClassItem directly as the target for the trampoline:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Exercise
{
class Program
{

static void Main(string[] args)
{
var obj = GetObjectSet();
//We know obj is an ObjectSet<T> for unknown T
var t = obj.GetType().GetGenericArguments()[0];
var parm = Expression.Parameter(typeof(object));
var objectSet = typeof(ObjectSet<>).MakeGenericType(t);
var method = typeof(Program).GetMethod("BuildClassItem", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(t);

var trampoline = Expression.Lambda(
Expression.Call(null, method, Expression.Convert(parm,objectSet)), new[] {parm});
var dele = (Action<object>) trampoline.Compile();
dele(obj);
Console.WriteLine("Done");
Console.ReadLine();
}

static void BuildClassItem<T>(ObjectSet<T> entities) where T : class
{
Console.WriteLine("We made it!");
}

static object GetObjectSet()
{
return new ObjectSet<string>();
}
}

internal class ObjectSet<T> where T:class
{
}
}

If you have more work to do between finding the type T and calling BuildClassItem you'd still want to put all of that logic inside a generic method in T and construct a void call into it. You can't "say" the name of the type from outside a generic method so you have no way of storing the returned value from your MyConvert function in a correctly typed variable. So you need to move all of the logic into it.

Java generics cast based on return type?

As SJuan67 explained, you cannot really use casts with generic types as Java compiler will

Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.

More info on all generics restrictions here.

So ButterKnife code will look like this:

  public Object castParam(Object paramObject, String paramString1, int paramInt1, String paramString2, int paramInt2)
{
return paramObject;
}

So to your questions:

Q: But the exception is not never caught, it gets thrown at the line when the method is called. Why is that?

A: Well its not even in the bytecode.

Q: Also, how does this work exactly? How does the method know what to cast to?

A: It doesn't. At least not like you think it will. In practice it will throw ClassCastException not IllegalStateException or AssertionError as you observed.
You can even try it with ButterKnife sample app and Bind a known TextView to CheckBox:

@Bind(R.id.title) CheckBox title;

Q: How does the library work then?

A: Well IllegalStateException is just never called and you have ClassCastException. Why it is like that I an not really sure. However as ButterKnife generates code this could be intended to prevent from compile errors.

for example:

public interface Some {
}

public static void weWantSome(Some d) {
}

public static void test() {
String o = "test";
weWantSome((Some)o); //<-- compile error
weWantSome(Main.<Some>cast(o)); //<-- runtime error
}

Which is why in the previous example code compiles but does not run.

Proper way to cast object to generic type

My suggestion is to change method getValiable(String name). You can pass Class<T> varClass to this method. And your signature will be something like that:

<T> T getVariable(String name, Class<T> varClass);

If this method is placed in 3rd party library, I would recommend to you to create some wrapper for this class.

class Wrapper {
private OriginalClass originalObject;

<T> T getVariable(String name, Class<T> varClass) {
return (T) originalObject.getVariable(name);
}
}

Cast generic type parameter to a specific type in C#

A better design is to put a constraint on it that is common between type T and the class you want to expect in your method, in this case SomeClass.

class SomeConsumer<T> where T : ISomeClass
{
void SomeMethod(T t)
{
ISomeClass obj2 = (ISomeClass) t;
}
}

interface ISomeClass{}

class SomeClass : ISomeClass {}

Edit based on edit of Question

That is bad design. Try to move that "operation" into the class itself so the caller does not have to know the type. If that is not possible share more of what is being done, what you want to accomplish though is that you do not have a stack of if/else statements where execution depends on the type of object being passed in to the method.

class SomeConsumer<T> where T : ISomeClass
{
void SomeMethod(T t)
{
ISomeClass obj2 = (ISomeClass) t;
// execute
t.Operation();
}
}

interface ISomeClass{
void Operation();
}

class SomeClass : ISomeClass {
public void Operation(){/*execute operation*/}
}

How to cast an object to a given generic type so I can pass this object to method

Okay, the solution is easy. All I had to do is remove <?> from "EVENTS" array and just use "isAssignableFrom" to check if listener implements given event type. It works now.

Why does casting a generic return type to another generic type work?

You are not “casting a generic return type to another generic type”. When a method declares a type variable, the immediate caller of the method decides what to substitute for the type parameter. When no bound has been specified for the type parameter, any reference type can be used. We could invoke Test.<Object>fail(), or Test.<Character>fail(), or even Test.<Thread>fail(). When we don’t specify an explicit type for an invocation, the compiler will infer a type from the context.

Since the main method invokes the fail() method, it can choose a type argument for R to make the containing expression applicable to the invocation of valueOf. In contrast, main declares the T type parameter and has no control over it; choosing an actual type argument for T is up to main’s caller. All main can assume, is that it will be assignable to Object (as no other bound has been given).

So, the key point is that T is a type that main can’t convert to a numeric type. Just like with (Object)fail() or Test.<Object>fail(). The caller could use an actual type for T that is convertible to a numeric type but that can’t change the logic within the main method.

Instead of casting to (T), you could also just write Test.<T>fail() to tell the compiler that you want use T for R. In either case, you prevent the compiler from inferring a type argument for R from the surrounding context.


The JLS section linked in your question is not about “Poly expressions in Conditional expressions” but only about the different forms of Conditional expressions and you have to resolve the type of the Poly expression first, before you can determine which kind of Conditional expression you have.

As said, without an explicit type argument and without the type cast, the target type determines the type for <R> for the generic invocation of fail(). When you invoke String.valueOf(Object), the target type is Object, but when you invoke String.valueOf(char), the target type is char.

Both works, as you also can write

char c = true? 'a': fail();

Object o = true? 'a': fail();

In the second case, Object is inferred for <R> and the combination of char and Object from Table 15.25-E applies, which defines the result to be lub(Character,Object). Which is Object.

But in the first case, Character will be inferred for <R>, so the combination of char and Character from Table 15.25-C applies, defining the result to to be char.

Note that this is a numeric conditional expression which allows a variety of type conversions.

We could also write

int i = true? 'a': fail();

which promotes the char to int and infers Integer for fail()’s <R> (though it would also work if fail() returned Character, Short, or Byte). So valueOf(int) is also applicable here, but since valueOf(char) is more specific, this does not contribute to the ambiguous method invocation error.

So after ruling out all inapplicable and less specific methods, valueOf(char) and valueOf(Object) remain and neither is more specific, so the compiler error is generated.

When you insert the cast to T, which is not convertible to a numeric type, you have a Reference Conditional Expression whose result is lub(Character,T), which evaluates to Object. Then, only String.valueOf(Object) is applicable.



Related Topics



Leave a reply



Submit