How to check if a generic type implements a specific type of generic interface in java?
Java implements erasure, so there's no way to tell on runtime if genericObject
is an instance of Set<String>
or not. The only way to guarantee this is to use bounds on your generics, or check all elements in the set.
Compile-time Generic Bounds
Using bounds checking, which will be checked at compile-time:
public <T extends SomeInterface> void genericMethod(Set<? extends T> tSet) {
// Do something with tSet here
}
Java 8
We can use streams in Java 8 to do this natively in a single line:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (set.stream().allMatch(String.class:isInstance)) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
Java 7 and older
With Java 7 and older, we need to use iteration and type checking:
public <T> void genericMethod(T t) {
Set<String> strs = new HashSet<String>();
Set<?> tAsSet;
if (t instanceof Set<?>) {
tAsSet = (Set<?>) t;
for (Object obj : tAsSet) {
if (obj instanceof String) {
strs.add((String) obj);
}
}
// Do something with strs here
} else {
// Throw an exception or log a warning or something.
}
}
Guava
As per Mark Peters' comment below, Guava also has methods that do this for you if you can add it to your project:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (Iterables.all(set, Predicates.instanceOf(String.class))) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
The statement, Iterables.all(set, Predicates.instanceOf(String.class))
is essentially the same thing as set instanceof Set<String>
.
Assigning datatype to a generic type of variable based on a condition in Java
I changed the class names.
class SOQ<T>
{
T defaultValue;
String value;
}
class SOQ_Impl
{
private void test(String datatype)
{
switch (datatype)
{
case "Integer": {
SOQ<Integer> test = new SOQ<>();
test.defaultValue = 3;
actionsCommonForAllPossibleDataTypes(test);
break;
}
case "String": {
SOQ<String> test = new SOQ<>();
test.defaultValue = "dummy";
actionsCommonForAllPossibleDataTypes(test);
break;
}
}
}
private void actionsCommonForAllPossibleDataTypes(SOQ<?> test)
{
// some other actions common for all possible data types
}
}
You declared the type with a <?>
parameter, and that is what is causing you problems. I resolved this by not declaring the variable I was going to use until after I knew what type I wanted it to be.
Under what conditions is unit a type?
I believe the rule is that a method that is statically known to have return type unit
will be compiled to a .NET method with return type void
in the .NET type system (by statically known, I mean in contrast to a generic method or a method on a generic type which uses a type parameter as the return type). At invocations, the compiler hides the distinction between methods that return void
and methods that return true unit
values at the CLR level.
The problem in your example occurs because properly implementing the generic interface actually requires a unit
return type at the CLR level (and the CLR does care about the distinction between unit
and void
). In other words, the problem occurs if and only if you want to override a method which returns a type parameter of a generic class by a method which is statically known to return unit
(based on substituting unit
for that type parameter). By override here, I mean either implementing abstract methods on classes or interfaces or overriding non-sealed methods on classes.
As Tamil points out, one way to work around this limitation is to ensure that you use F# functions instead of methods. Another workaround is to introduce an extra concrete class into the hierarchy which has a dummy generic type parameter (say the extra class is T<'unit>
), and to return Unchecked.defaultof<'unit>
instead of ()
wherever that would cause problems. Then you can derive an additional non-generic concrete class T
from T<unit>
and everything will work fine.
Testing if object is of generic type in C#
If you want to check if it's an instance of a generic type:
return list.GetType().IsGenericType;
If you want to check if it's a generic List<T>
:
return list.GetType().GetGenericTypeDefinition() == typeof(List<>);
As Jon points out, this checks the exact type equivalence. Returning false
doesn't necessarily mean list is List<T>
returns false
(i.e. the object cannot be assigned to a List<T>
variable).
C# Generics and Type Checking
You could use overloads:
public static string BuildClause(List<string> l){...}
public static string BuildClause(List<int> l){...}
public static string BuildClause<T>(List<T> l){...}
Or you could inspect the type of the generic parameter:
Type listType = typeof(T);
if(listType == typeof(int)){...}
Generic class: conditional method based on type
Nope but you can probably accomplish something similar with interfaces
interface IMyType
{
//...what ever method/properties are shared for all
}
public class MyType<T> : IMyType
{
public T getValue() { return value; }
//...shared methods
}
public class MyTypeOtherSide : IMyType
{
//...shared methods
}
you'd then need to declare the variables as IMyType and only use MyType<T>
when you know that it is of that type
Related Topics
Differences Between Filtering Realm with Nspredicate and Block
Swiftui Share Sheet Crashes iPad
Swiftui - How to Get Coordinate/Position of Clicked Button
How to Apply a Grace Time Using Rx
Why Can't I Use Self in a Func Swift
Swift- How to Display Image Over Button
Applewatch Messages Url Works Hard Coded But Not with Variables
Avplayer Seektotime Not Working Properly
Selectively Remove and Delete Objects from a Nsmutablearray in Swift
Swift Repl: How to Save/Load the Repl State? (A.K.A. Suspend/Resume, Snapshot, Clone)
Classes in Swift Files Inside Folder References Not Seen by Xcode 10's Compiler
Non-Modular Headers of Openssl Library When Using Modulemap for Swift Framework
C-Style Uninitialized Pointer Passing in Apple Swift