Replies: 33 comments 1 reply
-
It's not guaranteed the enum backing field is an |
Beta Was this translation helpful? Give feedback.
-
I thought about that, what about something like this: public void DoSomething<T>(List<T> list)
where T : Enum, int
{
T first = list.FirstOrDefault();
int value = (int) first;
} |
Beta Was this translation helpful? Give feedback.
-
You could force it with dynamic: public void DoSomething<T>(List<T> list)
where T : Enum
{
T first = list.FirstOrDefault();
int value = (dynamic) first;
} Which actually gets compiled to: public void DoSomething<T>(List<T> list)
where T : Enum
{
T first = list.FirstOrDefault();
int value = (int) (object) first;
} |
Beta Was this translation helpful? Give feedback.
-
In my code I solved it casting the Enum as an object and to int... I suppose that this could incur in object casting and performance cost. Will dynamic be more performant? Thanks for the suggestion, but not having to do this tricks would be ideal. |
Beta Was this translation helpful? Give feedback.
-
It gets compiled to identical code in this case. The real cost here is of course boxing and unbocing, not casting which is essentially free. If this is really performance critical you could use unsafe code, or even call System.Runtime.CompilerServices.Unsafe.As<TFrom, TTo>, which would avoid boxing |
Beta Was this translation helpful? Give feedback.
-
I recall reading that in .NET 4.something the boxing/unboxing gets optimized out by the JIT in generic methods. |
Beta Was this translation helpful? Give feedback.
-
Nevermind, scratch that. Possible future optimization? For this method: int GetValue1<T>(T value)
{
return (int)(object)value;
} The JIT is smart enough to optimize out the box/unbox if |
Beta Was this translation helpful? Give feedback.
-
using System;
using System.Runtime.CompilerServices;
public static class EnumExtension
{
// size-specific version
public static TInt AsInteger<TEnum, TInt>(this TEnum enumValue)
where TEnum : unmanaged, Enum
where TInt : unmanaged
{
if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<TInt>()) throw new Exception("type mismatch");
TInt value = Unsafe.As<TEnum, TInt>(ref enumValue);
return value;
}
// long version
public static long AsInteger<TEnum>(this TEnum enumValue)
where TEnum : unmanaged, Enum
{
long value;
if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<byte>()) value = Unsafe.As<TEnum, byte>(ref enumValue);
else if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<short>()) value = Unsafe.As<TEnum, short>(ref enumValue);
else if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<int>()) value = Unsafe.As<TEnum, int>(ref enumValue);
else if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<long>()) value = Unsafe.As<TEnum, long>(ref enumValue);
else throw new Exception("type mismatch");
return value;
}
} |
Beta Was this translation helpful? Give feedback.
-
@ufcpp how about unsigned? 😄 |
Beta Was this translation helpful? Give feedback.
-
@ufcpp |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h @YairHalberstadt |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt Wait a sec...it definitely does not. That dynamic cast can't possibly compile to the identical code above. Written the way you have it: int value = (dynamic) first; That line of code needs to look for an implicit conversion between whatever type Even if you add an explicit cast there's still no way it emits the same code. The explicit dynamic cast will work fine for something like a This all involves dynamic call site binding if you start using |
Beta Was this translation helpful? Give feedback.
-
@mikernet |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt Look at the IL view in SharpLab. That's not the code that gets emitted. It's decompiler either has a bug or intentionally changes the code, but that's not what actually gets emitted and the performance of the emitted code isn't the same as it's decompiled view. |
Beta Was this translation helpful? Give feedback.
-
Your dynamic method doesn't even work - it throws a ( |
Beta Was this translation helpful? Give feedback.
-
Have you considered |
Beta Was this translation helpful? Give feedback.
-
@mburbea |
Beta Was this translation helpful? Give feedback.
-
@ufcpp Yes I know. The only additional overhead my method has is a generic cached delegate invocation which is why it runs at almost the same speed. 10 million conversions using your method took 19ms, mine took 27ms. I know |
Beta Was this translation helpful? Give feedback.
-
@svick, sure, but if you're blindly assuming that the type is an int. Are you really concerned? If the type isn't long or ulong, you'll get the desired result. This is still safer than the suggested |
Beta Was this translation helpful? Give feedback.
-
@mburbea Just because There's always my solution if you don't like unsafe code :) |
Beta Was this translation helpful? Give feedback.
-
Sorry, I retract my objection. That |
Beta Was this translation helpful? Give feedback.
-
@alexdrl: maybe you could define a converter (?): public static class EnumConverter<TInput, TOutput>
where TInput: struct, Enum
where TOutput : struct, IConvertible
{
public static readonly Func<TInput, TOutput> Convert = GenerateConverter();
private static Func<TInput, TOutput> GenerateConverter()
{
var parameter = Expression.Parameter(typeof(TInput), typeof(TInput).Name);
var dynamicMethod = Expression.Lambda<Func<TInput, TOutput>>
(
Expression.Convert(parameter, typeof(TOutput)),
parameter
);
return dynamicMethod.Compile();
}
} And then you could call it either directly or define an extension method for the specific enum type you want to cast to int: public static int ToInt(this MySpecificEnum source)
{
return EnumConverter<MySpecificEnum, int>.Convert(source);
} |
Beta Was this translation helpful? Give feedback.
-
@Ultrahead I do not need the initial code anymore, and your code needs to know in advance that the enum is an integer. What I initially proposed is that the compiler supported the additional compiler check that the enum passed to the generic method has an underlying specific type (int, ulong...). So that my compile Will not compile if the passed enum does not have the specfied type. Thank you for your comments, I have learned a lot about .NET performance internals. |
Beta Was this translation helpful? Give feedback.
-
Alejandro: es bueno saberlo. I posted the code as a workaround, though, given its performace (it avoids boxing). I didn't see the proposal, besides the title it-self. Because even in the case you present, the compiler should know in advance your intent. Maybe a way to clearly state should be allowing something like: where T: Enum, int |
Beta Was this translation helpful? Give feedback.
-
@Ultrahead Yes, If the compiler knows the underlying type, why not having the possibility to use it as a generic method constraint? Or the compile does not know the underlying type for an enum? Maybe I should rephrase the issue title. |
Beta Was this translation helpful? Give feedback.
-
It does know but it's a matter of specifying your intent in the signature to guarantee and enforce compilation. That's why I mentioned: where T: Enum, int or even T: Enum(int) The title is ok. |
Beta Was this translation helpful? Give feedback.
-
There are probably a couple places I would use this if it was available since a compile time error is much nicer than a runtime error if you require an enum of a certain underlying type but that's such a niche situation that I can't imagine this will get a lot of priority. |
Beta Was this translation helpful? Give feedback.
-
Syntax wise I would imagine it would have to be more like the second example @Ultrahead gave because it's not actually an |
Beta Was this translation helpful? Give feedback.
-
@mikernet: yes, I realized that after posting the first syntax. I agree. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I am not being able to cast a generic method restricted type parameter to work like I supposed it worked.
I am missing something?
UPDATE:
What about something like:
Beta Was this translation helpful? Give feedback.
All reactions