Assuming that I have a generic class/method with a generic number constraint (using the new preview generic math feature):
public void DoAThing<TValue>(TValue value) where TValue : struct, INumber<TValue>
{
...
}
Is there a way to downcast this further to one of the other interfaces? For example, one of these sorts of things:
if (typeof(IFloatingPoint<TValue>).IsAssignableFrom(typeof(TValue)))
{
// do some floating-point-only logic without a specific value
}
if (value is IFloatingPoint<TValue> fpnum)
{
// do some floating-point-only logic on fpnum
}
Currently, the compiler objects to this, saying that TValue must be convertible to IFloatingPoint<TValue> to use it as a parameter... which is exactly what I'm trying to test.
Related
I am currently trying to get some casting on generic types done.
So the base idea is to have a method which accepts a generic Type and does different stuff depending on which type gets passed in.
For simplicity reasons I will just showcase the use of float, bool and default
The setup looks something like this (where T is a generic type defined by the class itself):
protected T DoStuff(T value)
{
switch (value) {
case float floatValue:
float result = DoFloatStuff(floatValue);
switch (result) {
case T output:
return output;
}
case bool boolValue:
bool result = DoBoolStuff(boolValue);
switch (result) {
case T output:
return output;
}
default:
// return value;
DoRealGenericStuff(value) // Edited, since I just want to sort out some special cases
}
}
Where DoFloatStuff and DoBoolStuff are just methods that have 1 parameter and a return type of their types respectively.
If I don't do it like that (I tried some typeof() casting before), the compiler always complains that it cannot cast from T to float and vice versa, even tho I made sure that would be the case with some Case-Switch / If-Else statements.
Does anybody know some better way to do this?
Thanks in advance,
BOTHLine
Edit:
Since a lot of people said kind of the same thing, that I either shouldn't use generics at all in a case like that or my methods would need to be more generic themselves..
My problem here is that I need to use 3rd party methods to handle the special cases I'm checking for (in this case the float and bool types). For the default case I already handled everything in a generic way. But for some defined types I just can't do that.
So to go a little more in detail why that's the case:
I'm currently working on a Plugin for the "Unity Engine". Unity has built in methods to display types (kind of all primitive types and some Unity-specific types). I have a generic Wrapper class which should be able to contain any types. But then when I want to display the content of that wrapper in the GUI that Unity Editor offers, I have to use the built-in methods to display the primitives (something like UnityEditor.EditrGUI.FloatField()). Without those methods I am never able to display anything.
Anything else which can be broken down to those types can then be displayed in a more generic way.
So the base idea is to have a method which accepts a generic Type and does different stuff depending on which type gets passed in.
That is the wrong idea. It's not the way generics should be used. In such a case, you should use method overloading to create the DoStuff for each type individually:
float DoStuff(float value) {/* float implementation here */}
bool DoStuff(bool value) {/* bool implementation here */}
...
The point of generic is to enable you to write a code that will run the same on different types - so it should either be used where the type itself is irrelevant to the code (like in any generic collection) or can be executed with an interface or a base class all the acceptable types implement (or inherits). At this point, generics is usually only needed when you want a method to return a specific implementation of an interface (or base class).
Let the compiler sort it out for you:
protected void DoStuff(float v){}
protected void DoStuff(int v){}
// and so on
//and finally the default:
protected void DoStuff(object v){}
public void Work(T value)
{
DoStuff(value)
}
This is not the short answer but it's the right way (by many standards). There might be a short answer but, if I were you I wouldn't bother.
This is the smell of a factory pattern. A generic should be, as the name suggests, generic and indifferent to the types if it is you can do something like this.
interface IDoStuffer<T>
{
T DoStuff(T value)
}
class DoStuffFloat : IDoStuff<float>
{
public float DoStuff(float value)
{
//Do your float stuff
}
}
class DoStuffBool : IDoStuff<bool>
{
public bool DoStuff(bool value)
{
//Do your bool stuff
}
}
Then you can have a factory give you a correct implementation
class DoStuffFactory
{
public IDoStuff<T> GetDoStuff<T>()
{
if(typeof(T) == typeof(float))
return new DoStuffFloat();
//And other types
}
}
I came across this problematic quite often: I like to overload some method with same parameters for different return types, but .NET refuses generic constraints to sealed classes/primitives. I'll refer to this pattern as phantom generics.
I know an ugly workaround: Putting every single interface the type implements behind the where statement.
My Question: Is there any way to use explicit types in generics to illustrate the return type and keep methods distinct?
Here is my code:
public static class Reinterpret {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(int value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value); //reinterpret the bytes of 'value' to a float
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(uint value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(long value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(ulong value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
}
Here's one slightly different way of approach it:
// Constraints just to be vaguely reasonable.
public static class Reinterpret<T> where T : struct, IComparable<T>
{
public T Cast(int value) { ... }
public T Cast(uint value) { ... }
public T Cast(float value) { ... }
public T Cast(double value) { ... }
// etc
}
For the implementation, you could just have a Func<int, T> field, a Func<double, T> field etc, and then have a big static constructor:
static Reinterpret()
{
if (typeof(T) == typeof(int))
{
// Assign all the fields using lambda expressions for ints.
// The actual assignment might be tricky, however - you may
// need to resort to some ghastly casting, e.g.
castDouble = (Func<double, T>)(Delegate)(Func<double, int>)
x => *((double*)&value;
}
....
}
Then for any type you didn't want to support, the fields would be null. Each Cast method would look like:
if (castIntMethod != null)
{
return castInt(value);
}
throw new InvalidOperationException("...");
To be honest, this isn't something I'd really want to do. I'd generally just use BitConverter. But it's an option.
Generics are not templates. They do not act like templates. They cannot be made to act like templates.
A "phantom" generic parameter is not going to help you simulate templates (and reinterpret_cast is not an actual template, anyway), because you soon are going to run into the fact that generics do not support specialization.
In particular, you asked "Is there any way to use explicit types in generics to ... keep methods distinct?" and commented that "the generic constraints ... keeps [sic] the methods distinct". But they actually do not. These methods are distinct only because the argument types are different. Generics are computed from overloads, they do not influence overloading.
This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 8 years ago.
Suppose I have an unconstrained generic method that works on all types supporting equality. It performs pairwise equality checks and so works in O(n2):
public static int CountDuplicates<T>(IList<T> list)
{
/* ... */
}
I also have a constrained generic method that only works with types supporting sorting. It starts from sorting the list in O(n log n), and then counts all duplicates in one pass:
public static int CountDuplicatesFast<T>(IList<T> list)
where T : IComparable<T>
{
/* ... */
}
So, a caller can choose to invoke the fast method if it is statically known that the type of elements of the list supports ordering. It might happen that the caller itself works with generic IList<T> where T is unconstrained, so its only option to invoke the first (slow) method.
Now, I want the first method to check at runtime if the type T actually implements the interface IComparable<T> and if so, invoke the fast method:
public static int CountDuplicates<T>(IList<T> list)
{
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast(list);
}
else
{
/* use the slow algorithm */
}
}
The problem is the compiler rejects the invocation CountDuplicatesFast(list):
error CS0314: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Program.CountDuplicatesFast<T>(System.Collections.Generic.IList<T>)'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IComparable<T>'.
Is it possible to persuade the compiler to trust me that I know what I am doing, and to skip the constraint check?
You can use a helper class and dynamic type to skip compile-time checks:
sealed class CountDuplicatesFastCaller
{
public int Call<T>(IList<T> list) where T : IComparable<T>
{
return CountDuplicatesFast(list);
}
}
public static int CountDuplicates<T>(IList<T> list)
{
if (typeof (IComparable<T>).IsAssignableFrom(typeof (T)))
{
return ((dynamic) new CountDuplicatesFastCaller()).Call(list);
}
else
{
/* use the slow algorithm */
}
}
This should be faster than pure reflection because of DLR caching mechanisms.
Here's a way to do it using dynamic:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
return CountDuplicatesFast((dynamic)list);
}
Or with reflection:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
var method = typeof(MyType).GetMethod("CountDuplicatesFast");
var generic = method.MakeGenericMethod(typeof(T));
return (int)generic.Invoke(null, new object[] { list });
}
I don't think that there's a way to do this statically (i.e. without reflection or dynamic).
I have a class with a dictionary that maps Type keys to objects that implement some interface IWhatever.
I wish to create a generic function that gets a Type as input and returns the object mapped to that type in the dictionary.
Something like :
public T get<T>(Type type)
Where T is an instance of type and type implements IWhatever.
I don't want to return Object or even Iwhatever but objects of the given type. the type of the return objects can clearly be infered at compile time. so I assume it should be possible.
I have managed to do this in java:
public T get<T>(Class<T extends IWhatever> type) { // implementation }
Is there any way to achieve this in C# ? if not, why not and what alternatives would you suggest ?
I think you want:
public T Get<T>() where T : IWhatever { ... }
For more information, see Constraints on Type Parameters (C# Programming Guide).
This is of course only useful when the client can provide the type argument easily at compile-time. Internally, your method may need a lot of nastiness, e.g.:
return (T) myDict[typeof(T)];
I think you are being misled by Java's erasure. Consider the following Java code from your post (edited to make it valid code):
public <T extends IWhatever> T get(Class<T> type) { // implementation }
In this case, the type parameter is only required because the generic type information is only available at compile time. This is not true in C#, where you can write the following:
public T Get<T>()
where T : IWhatever
{
Type type = typeof(T);
// rest of implementation
}
From your first two sentences, what you want I think is the following. You have to decide on some attribute of your types that will be unique. You could make sure that all the types you have include the GUID attribute.
public class MyClass
{
private Dictionary<GUID, object> _myDictionary;
public AddObject(object objectToAdd)
{
_myDictionary.Add(objectToAdd.GUID, objectToAdd);
}
public object GetObject(Type typeToGet)
{
return _myDictionary[typeToGet.GUID];
}
}
If the dictionary needs to contain multiple objects of each type, then the dictionary values can be lists of objects.
public static object GetObject(int x)
{
return new object { };
}
public static object GetObject(string x)
{
return new object { };
}
public static void ProcessObject<T>(T x) where T : int, string <= got error here:
{
object o = GetObject(x);
}
Got error "A type used as a constraint must be an interface, a non-sealed class or a type parameter."
How can I rewrite the code to get it work without write ProcessObject(int x) and ProcessObject(string x) twice?
So what you have now (according to accepted answer and your comments) is:
public static void ProcessObject<T>(T x)
{
object o;
if (typeof(T) == typeof(int))
o = GetObject((int)(object)x);
else if (typeof(T) == typeof(string))
o = GetObject((string)(object)x);
else
throw new Exception();
// do stuff with o
}
I'd recommend making public int and string overloads, but to prevent code duplication, internally call another method:
public static void ProcessObject(int x)
{
ProcessObject(GetObject(x));
}
public static void ProcessObject(string x)
{
ProcessObject(GetObject(x));
}
private static void ProcessObject(object o)
{
// do stuff with o
}
This makes your public methods' input values clear: int and string are the only acceptable types, while still not duplicating your actual logic (// do stuff with o).
You might dislike that the two public ProcessObject methods are duplicates of each other, (on the surface anyway; under the hood, they're calling two different GetObject overloads) but I think it's the best option.
You cannot do what you are trying to do: first, it is not possible to list several classes in a generic constraint; second, the type that you can put in a constraint must be such that you could inherit it (or implement it if it is an interface). Both int and string fail this check. In cases like this, you would be better off with two separate overloads.
Just remove the where part
public static void ProcessObject<T>(T x)
{
object o = GetObject(x);
}
And also don't use object in your other methods, instead use T
it's impossible in C# take a look on Constraints on Type Parameters. Try to use dynamic
Generally speaking, if your object reacts differently based on the generic type argument, you probably shouldn't be using generics in this case. Generics are great for situations where you want to do always the same thing, no matter what the actual type used.
Therefore, generic constraints will only allow you to list one base class for a type argument. Any actual types passed to the respective type arguments are meant to be a part of the given inheritance hierarchy starting with the base class you specified, so users of your class can specify any type that matches the base class or any of its subclasses.
At the same time, you, the author of the generic class, can safely assume that the specified type has (at least) the interface of the base class indicated by the constraint. Hence, you may access any members of the base class.
If you want to allow either string or int, imagine what members that could be. Both are derived directly from System.Object, hence the restriction would make no sense as it is no restriction; every type is derived from System.Object.
Summarizing, if you really want to treat string and int differently, this is definitely a case for offering two overloads rather than one generic class.