What is the C # equivalent of the Java <X> class?

In Java, itโ€™s convenient for the class to have a common parameter X. But the class of the C # class does not have this.

So, in C #, how to make the equivalent of the following Java code ?:

public <X> X methodThatReturns(Class<X> clazz) { ... } 

In C #, there is no way to connect these return values โ€‹โ€‹and the passed type.

Explanation
Several answers indicate that the method parameter is not needed because the method can simply be defined as methodThatReturns<X>() .

But if you have an unknown variable of type t , there is basically no way to call such a general method so that it returns a Type t object?

In Java, you can pass Class<X> variables without losing type information, but it seems that in C #, if you pass equivalent Type variables, you might run into constraints, t use them when you need to call common methods.

+6
source share
4 answers
 public X methodThatReturns<X>(Class<X> clazz) { ... } 

Also keep in mind that C # doesnโ€™t erase styles , so you can do things like typeof(T) without worries if the class is intended as an object of the Java class and not as a โ€œsome classโ€ placeholder:

 public X methodThatReturns<X>(X value) { Type x = typeof(X); // that fine if (value is SomeType) { } // that fine too return (X)someObject; // I think you get the point } 

Edit:

Again, since information of a general type is not lost after compilation, you do not need to explicitly pass this type:

 public X methodThatReturns<X>() { Type xType = typeof(X); // Type is to C#/.Net what Class<X> is to Java. } 
+9
source

In C # it will be

 public X methodThatReturns<X>() { ... } 

and you can get type X using typeof(X) instead of using the clazz parameter

+3
source

I am not 100% increasing Java generators ... Are you trying to declare a method that returns the same type as it was passed?

 public T MethodThatReturns<T>(T input) { ... } 

This method will be common to any type and returns the same type that was passed. You can call this using:

 AnyTypeAtAll foo = new AnyTypeAtAll(); AnyTypeAtAll bar = MethodThatReturns(foo); 

Please note that there is no <AnyTypeAtAll> when calling the MethodThatReturns method, the compiler can understand this taking into account the parameter you passed. However, note that this is done by the compiler, not runtime, so it will only use the type of the variable foo, not the type of object pointed to by foo.


On the other hand, if this Java syntax for a method that does not accept "real" parameters is simple:

 public T MethodThatReturns<T>() { Type clazz = typeof(T); .... } 

Within this method, you can handle T just like any other class, and it will refer specifically to the type with which the method was called, and not to object or something like that. You can put where T : class to allow comparison with a null value in this method (which does not allow using int as a generic type) or where T : new() to restrict the generic type to the default constructor, so you can do T foo = new T();

+1
source

I am familiar with both Java and .NET generators, and I use the Class<X> construct so well as in my Java projects. One of my favorite uses is to consider non-generic collections in Java that come back from external code such as Hibernate (I think the latest version of Hibernate can support generics, although I'm not sure about that. We are using a rather old version, since this a long-running project in which there is too much code that needs to be updated if we ever changed it.) The function works as follows:

 public <X> List<X> TypedList(List<?> lst, Class<X> cls) { return (List<X>) lst; } 

Everything is very simple, and the important thing is that I do not need to create a dummy object to pass the function to, I just call it:

 List<MyObject> myLst = TypedList(lst, MyObject.class); 

Another important thing is to note that the cls parameter is not used at all. This only means providing a specific type for X.

The way you do this is slightly different from C #. You might think that the same function would look something like this:

 public List<X> TypedList<X>(IList lst) { return (List<X>) lst; } 

But you would be wrong.

The problem is that Java uses a trick called Type Erasure, which basically means that when the code is really compiled, ALL common parameters are removed from the code. Thus, in the world of the Java virtual machine, there is no such thing as List<X> or any other generics, they are all simple List and other non-generic types. This means that generators are only available to help you code and not execute at run time.

In C #, however, erasing styles and generics not executed at run time. This means that when used with the above function, an exception is thrown at runtime:

 List<object> lstObj = TypedList<object>(new List<string>()); 

The reason is that List<string> and List<object> are considered two completely different classes. You can't even do List<object> lstObj = (List<object>) new List<string>(); without getting a compiler error. This means that the function cannot return the same object that was passed to it. We must create a new object of the correct type and return it. The most basic form of this will look like this:

 public List<X> TypedList<X>(IList lst) { List<X> lstOut = new List<X>(); for (int i = 0; i < lst.Count; i++) { if (lst[i] is X) lstOut.Add((X) lst[i]); } return lstOut; } 

This is pretty boring and boilerplate code, but it works. For something much shorter and cleaner, LINQ is here to save the day. Check the following:

 public List<X> TypedList<X>(IList lst) { return lst.OfType<X>().ToList(); } 

OfType<X>() captures all elements in lst that are of type X (or descendants) and skip any that are not. ToList() then creates a new List<X> containing all the elements passed to it from OfType<X>() . Another advantage of this method is that we can actually change the lst parameter from IList to IEnumberable , which is implemented by all types of collections.

Another thing to point out, however, is that it does not do any type conversion, but only type checking. This means that if you want to take a List<long> and convert it to List<int> or List<string> , you will need to do something else. With LINQ, it will still be very simple:

 List<long> lstLng = new List<long>(); lstLng.Add(1); List<int> lstInt = lstLng.Cast<int>().ToList(); List<string> lstStr = lstLng.Select(lng => lng.ToString()).ToList(); 

[NOTE. If you are not familiar with the lng => lng.ToString() , this is called a lambda expression.]

Cast<int>() , unlike OfType<int>() , actually tries to convert each element to int, skipping any elements that cannot be converted. Select() simply allows you to create a whole new collection from your existing collection using almost any code you want.

I hope my real-world examples help people better understand the differences between .NET and Java when it comes to using functions with generic types.

0
source

Source: https://habr.com/ru/post/886265/


All Articles