Let's say I have a generic class as follows:
public class GeneralPropertyMap<T>
{
}
In some other class I have a method that takes in an array of GeneralPropertyMap<T>. In Java, in order to take in an array that contains any type of GeneralPropertyMap the method would look like this:
private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}
We use the wildcard so that later we can call TakeGeneralPropertyMap passing a bunch of GeneralPropertyMap with any type for T each, like this:
GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
//And finally pass the array in.
TakeGeneralPropertyMap(maps);
I'm trying to figure out an equivalent in C# with no success. Any ideas?
Generics in C# make stronger guarantees than generics in Java. Therefore, to do what you want in C#, you have to let the GeneralPropertyMap<T> class inherit from a non-generic version of that class (or interface).
public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
// Only you can implement it:
internal GeneralPropertyMap() { }
}
Now you can do:
private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}
And:
GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);
While, as others have noted, there's no exact correspondence to wildcards in c#, some of their use cases can be covered with covariance/contravariance.
public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so
// we need to introduce an interface...
public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class
// inherit from it
//now our method becomes something like
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){}
// and you can do
var maps = new List<IGeneralPropertyMap<Object>> {
new GeneralPropertyMap<String>(),
new GeneralPropertyMap<Regex>()
};
//And finally pass the array in.
TakeGeneralPropertyMap<Object>(maps);
The caveat is that you can't use covariance with value types, so adding a new GeneralPropertyMap<int>() to our list fails at compile time.
cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'
This approach may be more convenient than having a non-generic version of your classes/interfaces in case you want to constrain the types that GeneralPropertyMap can contain. In that case:
public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {}
allows you to have:
var maps = new List<IGeneralPropertyMap<IMyType>> {
new GeneralPropertyMap<A>(),
new GeneralPropertyMap<B>() ,
new GeneralPropertyMap<C>()
};
TakeGeneralPropertyMap(maps);
There is no direct equivalent to this in C#.
In C#, this would often be done by having your generic class implement a non-generic interface or base class:
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
You could then pass an array of these:
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);
Make an interface from the members of GeneralPropertyMap (IGeneralPropertyMap), and then take an IGeneralPropertyMap[] as an argument.
Actually, you can get pretty close to a wildcard by using dynamic. This also works nicely if you have a non-generic superclass.
For example:
public class A
{
// ...
}
public class B<T> : A
{
// ...
}
public class Program
{
public static A MakeA() { return new A(); }
public static A MakeB() { return new B<string>(); }
public static void Visit<T>(B<T> b)
{
Console.WriteLine("This is B with type "+typeof(T).FullName);
}
public static void Visit(A a)
{
Console.WriteLine("This is A");
}
public static void Main()
{
A instA = MakeA();
A instB = MakeB();
// This calls the appropriate methods.
Visit((dynamic)instA);
Visit((dynamic)instB);
// This calls Visit(A a) twice.
Visit(instA);
Visit(instB);
}
}
How this works is explained in the C# documentation here.
Related
I have an interface with a type parameter that allows its conversion into the same type with another type parameter. Like this:
interface Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f);
}
I now want to impose a stricter requirement on the return type: I want the convert method to only return the same type as it was called on. Like this:
class GoodInterfaze<A> implements Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f) {
// return new GoodInterfaze<B>(); // I want this to be allowed by compiler
// return new BadInterfaze<B>(); // I want this to be a compilation error
return null;
}
}
class BadInterfaze<A> implements Interfaze<A> {
public <B> Interfaze<B> convert(java.util.function.Function<A, B> f) {
// return new GoodInterfaze<B>(); // I want this to be a compilation error
// return new BadInterfaze<B>(); // I want this to be allowed by compiler
return null;
}
}
The Interfaze interface is under my control, so I can add extra type parameters to it (or its methods) when needed. Do Java generics allow for anything like this?
You can get close by doing this.
public interface Interfaze<T extends Interfaze<T>> {
T convert();
}
Then you can do
public class Main {
public static class Good implements Interfaze<Good> {
#Override
public Good convert() { return new Good(); } // Compiles
}
public static class Bad implements Interfaze<Bad> {
#Override
public Bad convert() { return new Good(); } // Doesn't compile
}
}
This idea of using recursive bounds like this is very common. I personally dislike it as it's very confusing and because it doesn't mix well with inheritance. For example, you can't make a subclass SubGood of Good that implements Interfaze<SubGood> because you can't implement the same generic interface with 2 different type arguments. It only really works if all implementing classes cannot be extended (that's why Enum<E extends Enum<E>> is ok).
I have a class like this
class Dummy{
public getData(Info info){
List<SomeType> list = info.getDataAsPerInfo();
List<SomeType> result=new List<>();
for(SomeType someType: list){
// extracting data from someType, lets say this data is
// resType (it also of SomeType)
result.add(resType);
}
}
public static void main(String args[]){
Info1 info = new Info1(); // Info1 extends Info
// adding paramters to info
new Dummy().getData(info);
}
}
Now the problem is that I have several Info classes like Info1, Info2 ...
and there getData method might return different types of list. I can't figure how to achieve this without rewriting the code for each and every Info class( this would involve replacing SomeType with the return type of that class' getdataAsPerInfo function).
Is there a way such that I can somehow use SomeType according to the Info type that is passed to the getData function? What would be the best approach in this case? Thanks !!
Just take a look at the Oracle tutorial for Generics.
You can't only define one specific class as the type for your lists elements but also families of classes or classes implementing a specific interface.
edit to incorporate comments.
When your Info.getDataAsPerInfo() returns Lists of different Objects depending on which InfoX class is used, this would be a use case for a generic interface.
public interface Info<T> {
List<T> getDataAsPerInfo();
}
with implementations like:
public class Info1 implements Info<SomeType>
or
public class Info2 implements Info<SomeOtherType>
Then your Dummy-class would look like
class Dummy {
public getData(Info<T> info) {
List<T> list = info.getDataAsPerInfo();
List<T> result=new List<>();
for(T someType: list){
// extracting data from someType, lets say this data is
// resType (it also of SomeType)
result.add(resType);
}
}
public static void main(String args[]){
Info1 info = new Info1(); // Info1 extends Info<SomeType>
// adding paramters to info
new Dummy().getData(info);
}
}
I don't think you need to fiddle with generics here. You are looking for a solution where you could decide the functionality of SomeType in runtime (polymorphically). Have look at this solution.
private interface SomeType {
void doAThing();
}
private class AnotherType implements SomeType {
#Override
public void doAThing() {
System.out.println("AnotherType.doAThing");
}
}
private class OneMoreType implements SomeType {
#Override
public void doAThing() {
System.out.println("OneMoreType.doAThing");
}
}
private abstract class Info {
public abstract SomeType getDataAsPerInfo();
}
private class Info1 extends Info {
#Override
public SomeType getDataAsPerInfo() {
return new AnotherType();
}
}
private class Info2 extends Info {
#Override
public SomeType getDataAsPerInfo() {
return new OneMoreType();
}
}
Now you can return SomeType from Info and specifically implement the functionality in subclasses.
If the info of each class is a different type but either extends or implements a main supertype you can use List< ? extends Type > which would work
You could always use List< ? > which returns any value as the generic, it's basically an unknown object so just have getData return List< ? > and it should work fine, then check they type with "instanceof" or other ways of doing it, this should work for what you're trying to achieve.
Or for the method you're using (it looks like) you can use T settings, here's a snippet of code with what I think you're trying to achieve.
public <T> List<T> getInfo(T type) {
// T here would be the type
return new ArrayList<T>();
}
Your question is kind of ambiguous so if you could explain more of what you're trying to do then I could help a lot more.
Consider the following classes
public interface SortBy<S> {
}
public class CommentSortBy<S> implements SortBy<S> {
public static CommentSortBy<Date> CREATION = new CommentSortBy<Date>();
public static CommentSortBy<Integer> VOTES = new CommentSortBy<Integer>();
}
public class SomeQueryUnsafe {
public <M, S extends SortBy<M>> void setSort(S sortBy, M min) {
//Set relevant values
}
}
This is currently used as:
public SomeQueryUnsafe createCommentQueryUnsafe() {
return new SomeQueryUnsafe();
}
public void test() {
createCommentQueryUnsafe().setSort(CommentSortBy.CREATION, new Date());
}
While this works, the problem is that createCommentQueryUnsafe() does not specify limits on sortBy. Users are free to pass UserSortBy.NAME even though that would make no sense in this context
I can't figure out how to do write this though because just adding <B extends SortBy> to the class signature means I loose the ability to restrict the min parameter in the method. I can't use something like <M, S extends B & SortBy<M>> as its a compiler error. Other attempts with wildcard magic just result in significantly more complexity and compiler errors. Moving the sorting to the createCommentQuery() method would mean every single query needs 2 methods, which is a crazy amount of duplicated code
How can I possibly write the generics so createCommentQuery() limits the sortBy parameter to just CommentSortBy while still having min restricted to the S parameter in the SortBy class?
This is indeed a tricky issue for the reasons you've pointed out. I tried various approaches but they were all defeated by the generics limitation you cited. Ultimately it seems like you'll need to make some design changes if you want the specified type safety.
Using the inheritance hierarchy of the SortBy implementations for your generic type restrictions seems to have led to this impasse in particular. I tried decoupling that restriction into a new type parameter on SortBy, which stands for the queried object itself, e.g. Comment, User, etc. This is the design I came up with:
static class Comment { }
static class User { }
interface SortBy<T, M> { }
static class CommentSortBy<M> implements SortBy<Comment, M> {
static final CommentSortBy<Date> CREATION = new CommentSortBy<Date>();
static final CommentSortBy<Integer> VOTES = new CommentSortBy<Integer>();
}
static class UserSortBy<M> implements SortBy<User, M> {
static final UserSortBy<String> NAME = new UserSortBy<String>();
}
static class Query<T> {
public <M> void setSort(SortBy<T, M> sortBy, M min) {
//Set relevant values
}
}
public static void main(String[] args) {
new Query<Comment>().setSort(CommentSortBy.CREATION, new Date());
new Query<Comment>().setSort(UserSortBy.NAME, "Joe"); //compiler error
}
(ideone)
I have a usual interface(that i do not want to make generic) with generic method Get and a generic class, that implements it.
#Override does not give me a warning and the code works as intended, but i have a warning in Foo#Get() :
Type safety: The return type T for Get() from the type Test.Foo<T> needs unchecked conversion to conform to TT from the type Test.Attribute
Must i make Attribute Interface generic as well? I am trying to avoid manual messing with Object and casts and store all types of different attributes in a list.
(using static just to compile the test sample in one file - it does not change anything)
import java.util.ArrayList;
import java.util.List;
public class Test
{
static interface Attribute
{
<TT> TT Get();
}
static class Foo<T> implements Attribute
{
T val;
public Foo(T val)
{
this.val = val;
}
#Override
public T Get()
{
System.out.println("it is me");
return val;
}
}
public static void main(String[] args)
{
List<Attribute> list = new ArrayList<Attribute>();
list.add(new Foo<String>("test"));
String s = list.get(0).Get();
System.out.println(s);
}
}
You could make the Attribute interface generic, and then use a wildcard to allow Attributes of any type to be placed in a List:
List<Attribute<?>> list = new ArrayList<Attribute<?>>();
If you need to ensure that only one Attribute of each type can be placed in the container, just use a Set:
Set<Attribute<?>> set = new HashSet<Attribute<?>>();
In order to use the interface without casting you will need to make the interface generic.
import java.util.ArrayList;
import java.util.List;
public class Test
{
static interface Attribute<E> //Added Generic Param
{
<E> E Get();
}
static class Foo<T> implements Attribute<T> //Added Generic Param
{
T val;
public Foo(T val)
{
this.val = val;
}
#Override
public T Get()
{
System.out.println("it is me");
return val;
}
}
public static void main(String[] args)
{
//Specify Type of generic
List<Attribute<String>> list = new ArrayList<Attribute<String>>();
list.add(new Foo<String>("test"));
String s = list.get(0).Get();
System.out.println(s);
}
}
The problem with the generic method in the base class is that someone could call it with an explicit type parameter. Which obviously would make no sense here, which is why the compiler is complaining.
It seems the best solution is to make your base class generic. If you want to store attributes of different types in a list, then you have a different problem; how are you going to get back to the original types (regardless of whether you're using generics)?
I want to use a generic class inside a nested static interface. My objective is to do something like this:
public class MyClass<T>{
private MyInterface task;
public static interface MyInterface{
void aMethod (T item);
}
}
But I get the error: Cannot make a static reference to the non-static type T. If I do some changes (below) I can use a generic type inside an interface, but I want to avoid this method because it's redundant to write the same class 2 times: one for MyClass and one for MyInterface.
public class MyClass<T>{
private MyInterface<T> task;
public static interface MyInterface<T>{
void aMethod (T item);
}
}
Thanks.
EDIT: I want to do this:
MyClass c = new MyClass<String> ();
c.setInterface (new MyClass.MyInterface (){
#Override
public void aMethod (String s){
...
}
);
or
MyClass c = new MyClass<AnotherClass> ();
c.setInterface (new MyClass.MyInterface (){
#Override
public void aMethod (AnotherClass s){
...
}
);
A static nested class or nested interface (which is always static, by the way) has no relation to its outer class (or interface) apart from namespace nesting and access to private variables.
So, the type parameter of the outer class is not available inside the nested interface in your case, you should define it again. To avoid confusion, I recommend using a different name for this inner parameter.
(As an example in the standard API, look for the interface Map.Entry<K,V>, nested inside the interface Map<K,V>, yet has no access to its type parameters and needs to declare them again.)
It's not redundant. With a static interface:
MyClass.MyInterface<String> myInstance;
and with a non-static innter class (an interface is always static):
MyClass<String>.MyInterface myInstance;
A more real world example:
Map<String, Integer> map = ...;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
...
}
The static approach has the advantage that you can import the nested type, and still specify the type parameters:
class ClassWithAReallyLongName<T> {
static interface Entry<T> {
}
}
and
import my.package.ClassWithAReallyLongName.Entry;
class Foo {
Entry<String> bar;
}
though one should use that idiom with caution as to not confuse the reader.