How do I check if a type fits the unmanaged constraint in C#?
How do I check if a type T
fits the unmanaged
type constraint, such that it could be used in a context like this: class Foo<T> where T : unmanaged
? My first idea was typeof(T).IsUnmanaged
or something similar, but that isn't a property/field of the Type
class
c# generics reflection types c#-7.3
add a comment |
How do I check if a type T
fits the unmanaged
type constraint, such that it could be used in a context like this: class Foo<T> where T : unmanaged
? My first idea was typeof(T).IsUnmanaged
or something similar, but that isn't a property/field of the Type
class
c# generics reflection types c#-7.3
That's a type constraint for a generic. I'm asking for a given typeT
, at runtime, how can I check if it is unmanaged or not?
– John
Dec 29 '18 at 11:04
add a comment |
How do I check if a type T
fits the unmanaged
type constraint, such that it could be used in a context like this: class Foo<T> where T : unmanaged
? My first idea was typeof(T).IsUnmanaged
or something similar, but that isn't a property/field of the Type
class
c# generics reflection types c#-7.3
How do I check if a type T
fits the unmanaged
type constraint, such that it could be used in a context like this: class Foo<T> where T : unmanaged
? My first idea was typeof(T).IsUnmanaged
or something similar, but that isn't a property/field of the Type
class
c# generics reflection types c#-7.3
c# generics reflection types c#-7.3
edited Dec 29 '18 at 12:08
Adrian
9,54511637
9,54511637
asked Dec 29 '18 at 11:00
JohnJohn
1931212
1931212
That's a type constraint for a generic. I'm asking for a given typeT
, at runtime, how can I check if it is unmanaged or not?
– John
Dec 29 '18 at 11:04
add a comment |
That's a type constraint for a generic. I'm asking for a given typeT
, at runtime, how can I check if it is unmanaged or not?
– John
Dec 29 '18 at 11:04
That's a type constraint for a generic. I'm asking for a given type
T
, at runtime, how can I check if it is unmanaged or not?– John
Dec 29 '18 at 11:04
That's a type constraint for a generic. I'm asking for a given type
T
, at runtime, how can I check if it is unmanaged or not?– John
Dec 29 '18 at 11:04
add a comment |
2 Answers
2
active
oldest
votes
According to unmanaged
constraint documentations:
An unmanaged
type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting.
Also it's mentioned in C# language design documentations about unmanaged type constraint:
In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:
- Have the type
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
orUIntPtr
. - Be any
enum
type. - Be a pointer type.
- Be a user defined struct that satisfies the
unmanaged
constraint.
Considerations
Usually calling MakeGenericType
is the most reliable solution for validating generic type constraints which are enforced by CRL. Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them. But be informed, at least at time of writing this answer, it's not working well for unmanaged
constraint.
.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences
but at the time of writing this answer, .NET Framework doesn't have such function. I should mention that even using IsReferenceOrContainsReferences
is not completely reliable for this task.
For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).
Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged
generic type constraint.
Option 1 - Using MakeGenericType
As an option, to check if the type can satisfy the unmanaged
constraint, you can use the following IsUnmanaged
extension method'.
Note: It is supposed to be more reliablesta, but I should say, it's not. It seems for
unmanaged
constraint, CLR is not respecting
the constraint and it's just a C# compiler feature. So at least for
now, I recommend using the second option.
using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
Option 2 - Writing your own method checking the documented rules
As another option, you can write your method checking documented rules for unmanaged
constraint. The following code has more rules rather than other answer to be able to handle cases like int?
or (int,int)
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
More Information
You may find the following links useful:
- Docs - Unmanaged constraint
- GitHub - C# 7.3 language design documents - Unmanaged type constraint
- A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
- A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
- GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
- GitHub - Proposal: Unmanaged constructed types #1504
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies onunmanaged
constraints.
– Reza Aghaei
Dec 29 '18 at 12:27
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there isRuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose
– John
Dec 29 '18 at 19:14
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
Option 1 doesn't work. I just tested it on a struct that has a string field and it returnedtrue
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check:T : struct
. And if you inspect the constraint info, you'll see that it's identical forT : struct
andT : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.
– madreflection
Jan 1 at 6:34
|
show 6 more comments
I am not sure if something like this already exists, but you could implement your own extension method similar to:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
1
@Groo I added more details to the answer because it seemsunmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected byMakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false whent.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)
– Reza Aghaei
Jan 1 at 14:21
|
show 2 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53968920%2fhow-do-i-check-if-a-type-fits-the-unmanaged-constraint-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
According to unmanaged
constraint documentations:
An unmanaged
type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting.
Also it's mentioned in C# language design documentations about unmanaged type constraint:
In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:
- Have the type
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
orUIntPtr
. - Be any
enum
type. - Be a pointer type.
- Be a user defined struct that satisfies the
unmanaged
constraint.
Considerations
Usually calling MakeGenericType
is the most reliable solution for validating generic type constraints which are enforced by CRL. Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them. But be informed, at least at time of writing this answer, it's not working well for unmanaged
constraint.
.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences
but at the time of writing this answer, .NET Framework doesn't have such function. I should mention that even using IsReferenceOrContainsReferences
is not completely reliable for this task.
For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).
Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged
generic type constraint.
Option 1 - Using MakeGenericType
As an option, to check if the type can satisfy the unmanaged
constraint, you can use the following IsUnmanaged
extension method'.
Note: It is supposed to be more reliablesta, but I should say, it's not. It seems for
unmanaged
constraint, CLR is not respecting
the constraint and it's just a C# compiler feature. So at least for
now, I recommend using the second option.
using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
Option 2 - Writing your own method checking the documented rules
As another option, you can write your method checking documented rules for unmanaged
constraint. The following code has more rules rather than other answer to be able to handle cases like int?
or (int,int)
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
More Information
You may find the following links useful:
- Docs - Unmanaged constraint
- GitHub - C# 7.3 language design documents - Unmanaged type constraint
- A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
- A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
- GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
- GitHub - Proposal: Unmanaged constructed types #1504
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies onunmanaged
constraints.
– Reza Aghaei
Dec 29 '18 at 12:27
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there isRuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose
– John
Dec 29 '18 at 19:14
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
Option 1 doesn't work. I just tested it on a struct that has a string field and it returnedtrue
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check:T : struct
. And if you inspect the constraint info, you'll see that it's identical forT : struct
andT : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.
– madreflection
Jan 1 at 6:34
|
show 6 more comments
According to unmanaged
constraint documentations:
An unmanaged
type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting.
Also it's mentioned in C# language design documentations about unmanaged type constraint:
In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:
- Have the type
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
orUIntPtr
. - Be any
enum
type. - Be a pointer type.
- Be a user defined struct that satisfies the
unmanaged
constraint.
Considerations
Usually calling MakeGenericType
is the most reliable solution for validating generic type constraints which are enforced by CRL. Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them. But be informed, at least at time of writing this answer, it's not working well for unmanaged
constraint.
.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences
but at the time of writing this answer, .NET Framework doesn't have such function. I should mention that even using IsReferenceOrContainsReferences
is not completely reliable for this task.
For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).
Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged
generic type constraint.
Option 1 - Using MakeGenericType
As an option, to check if the type can satisfy the unmanaged
constraint, you can use the following IsUnmanaged
extension method'.
Note: It is supposed to be more reliablesta, but I should say, it's not. It seems for
unmanaged
constraint, CLR is not respecting
the constraint and it's just a C# compiler feature. So at least for
now, I recommend using the second option.
using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
Option 2 - Writing your own method checking the documented rules
As another option, you can write your method checking documented rules for unmanaged
constraint. The following code has more rules rather than other answer to be able to handle cases like int?
or (int,int)
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
More Information
You may find the following links useful:
- Docs - Unmanaged constraint
- GitHub - C# 7.3 language design documents - Unmanaged type constraint
- A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
- A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
- GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
- GitHub - Proposal: Unmanaged constructed types #1504
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies onunmanaged
constraints.
– Reza Aghaei
Dec 29 '18 at 12:27
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there isRuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose
– John
Dec 29 '18 at 19:14
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
Option 1 doesn't work. I just tested it on a struct that has a string field and it returnedtrue
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check:T : struct
. And if you inspect the constraint info, you'll see that it's identical forT : struct
andT : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.
– madreflection
Jan 1 at 6:34
|
show 6 more comments
According to unmanaged
constraint documentations:
An unmanaged
type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting.
Also it's mentioned in C# language design documentations about unmanaged type constraint:
In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:
- Have the type
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
orUIntPtr
. - Be any
enum
type. - Be a pointer type.
- Be a user defined struct that satisfies the
unmanaged
constraint.
Considerations
Usually calling MakeGenericType
is the most reliable solution for validating generic type constraints which are enforced by CRL. Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them. But be informed, at least at time of writing this answer, it's not working well for unmanaged
constraint.
.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences
but at the time of writing this answer, .NET Framework doesn't have such function. I should mention that even using IsReferenceOrContainsReferences
is not completely reliable for this task.
For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).
Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged
generic type constraint.
Option 1 - Using MakeGenericType
As an option, to check if the type can satisfy the unmanaged
constraint, you can use the following IsUnmanaged
extension method'.
Note: It is supposed to be more reliablesta, but I should say, it's not. It seems for
unmanaged
constraint, CLR is not respecting
the constraint and it's just a C# compiler feature. So at least for
now, I recommend using the second option.
using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
Option 2 - Writing your own method checking the documented rules
As another option, you can write your method checking documented rules for unmanaged
constraint. The following code has more rules rather than other answer to be able to handle cases like int?
or (int,int)
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
More Information
You may find the following links useful:
- Docs - Unmanaged constraint
- GitHub - C# 7.3 language design documents - Unmanaged type constraint
- A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
- A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
- GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
- GitHub - Proposal: Unmanaged constructed types #1504
According to unmanaged
constraint documentations:
An unmanaged
type is a type that is not a reference type and doesn't contain reference type fields at any level of nesting.
Also it's mentioned in C# language design documentations about unmanaged type constraint:
In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:
- Have the type
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
,bool
,IntPtr
orUIntPtr
. - Be any
enum
type. - Be a pointer type.
- Be a user defined struct that satisfies the
unmanaged
constraint.
Considerations
Usually calling MakeGenericType
is the most reliable solution for validating generic type constraints which are enforced by CRL. Usually trying to implement validation by yourself is not a good idea because there may be a lot of rules which you should consider and there is always a chance for missing some of them. But be informed, at least at time of writing this answer, it's not working well for unmanaged
constraint.
.NET Core have a RuntimeHelpers.IsReferenceOrContainsReferences
but at the time of writing this answer, .NET Framework doesn't have such function. I should mention that even using IsReferenceOrContainsReferences
is not completely reliable for this task.
For example see the issue which I posted here about two structure which doesn't have any reference type but one of them evaluated as managed, one of them unmanaged (maybe a compiler bug).
Anyway, for now depending to your preference and requirements, use one of the following solutions to detect which type can satisfy unmanaged
generic type constraint.
Option 1 - Using MakeGenericType
As an option, to check if the type can satisfy the unmanaged
constraint, you can use the following IsUnmanaged
extension method'.
Note: It is supposed to be more reliablesta, but I should say, it's not. It seems for
unmanaged
constraint, CLR is not respecting
the constraint and it's just a C# compiler feature. So at least for
now, I recommend using the second option.
using System;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
class U<T> where T : unmanaged { }
public static bool IsUnManaged(this Type t)
{
try { typeof(U<>).MakeGenericType(t); return true; }
catch (Exception){ return false; }
}
}
Option 2 - Writing your own method checking the documented rules
As another option, you can write your method checking documented rules for unmanaged
constraint. The following code has more rules rather than other answer to be able to handle cases like int?
or (int,int)
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class UnmanagedTypeExtensions
{
private static Dictionary<Type, bool> cachedTypes =
new Dictionary<Type, bool>();
public static bool IsUnManaged(this Type t)
{
var result = false;
if (cachedTypes.ContainsKey(t))
return cachedTypes[t];
else if (t.IsPrimitive || t.IsPointer || t.IsEnum)
result = true;
else if (t.IsGenericType || !t.IsValueType)
result = false;
else
result = t.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance)
.All(x => x.FieldType.IsUnManaged());
cachedTypes.Add(t, result);
return result;
}
}
More Information
You may find the following links useful:
- Docs - Unmanaged constraint
- GitHub - C# 7.3 language design documents - Unmanaged type constraint
- A blog post by Sergey Teplyakov about Dissecting new generic constraints in C# 7.3
- A blog post by Maarten Balliauw about Unmanaged, delegate and enum type constraints
- GitHub Issue - Please clarify the implementation details of unmanaged generic constraints
- GitHub - Proposal: Unmanaged constructed types #1504
edited Jan 1 at 11:46
answered Dec 29 '18 at 11:40
Reza AghaeiReza Aghaei
65.5k854160
65.5k854160
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies onunmanaged
constraints.
– Reza Aghaei
Dec 29 '18 at 12:27
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there isRuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose
– John
Dec 29 '18 at 19:14
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
Option 1 doesn't work. I just tested it on a struct that has a string field and it returnedtrue
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check:T : struct
. And if you inspect the constraint info, you'll see that it's identical forT : struct
andT : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.
– madreflection
Jan 1 at 6:34
|
show 6 more comments
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies onunmanaged
constraints.
– Reza Aghaei
Dec 29 '18 at 12:27
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there isRuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose
– John
Dec 29 '18 at 19:14
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
Option 1 doesn't work. I just tested it on a struct that has a string field and it returnedtrue
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check:T : struct
. And if you inspect the constraint info, you'll see that it's identical forT : struct
andT : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.
– madreflection
Jan 1 at 6:34
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
Answer as it much quicker than the other answer, even if slightly more complex than the other. Thanks for the answer :)
– John
Dec 29 '18 at 12:24
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies on
unmanaged
constraints.– Reza Aghaei
Dec 29 '18 at 12:27
I also like the other answer, but to me, the code which is shared in my answer is more reliable and future proof as it relies on
unmanaged
constraints.– Reza Aghaei
Dec 29 '18 at 12:27
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there is
RuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose– John
Dec 29 '18 at 19:14
My edit was refused [ :( ], but i suggest you include the early check of whether it is primitive/pointer/enum below (it must be unmanaged) and then if it isnt a value type (in which case it can't be managed). Saves the expensive reflection for simple cases. Also worth adding - in .NET Core there is
RuntimeHelpers.IsReferenceOrContainsReferences<T>()
, an inbuilt function for this purpose– John
Dec 29 '18 at 19:14
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
@John I didn't see your edit, but will consider your comment and after some investigation I'll probably update the answer. Thanks for your comment :)
– Reza Aghaei
Dec 29 '18 at 19:16
Option 1 doesn't work. I just tested it on a struct that has a string field and it returned
true
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check: T : struct
. And if you inspect the constraint info, you'll see that it's identical for T : struct
and T : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.– madreflection
Jan 1 at 6:34
Option 1 doesn't work. I just tested it on a struct that has a string field and it returned
true
. Because the CLR doesn't enforce the constraint, it won't throw an exception if you provide a match for the constraint it can check: T : struct
. And if you inspect the constraint info, you'll see that it's identical for T : struct
and T : unmanaged
. The 'unmanaged' specifics are lost at runtime. Reminds me of generics in Java.– madreflection
Jan 1 at 6:34
|
show 6 more comments
I am not sure if something like this already exists, but you could implement your own extension method similar to:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
1
@Groo I added more details to the answer because it seemsunmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected byMakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false whent.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)
– Reza Aghaei
Jan 1 at 14:21
|
show 2 more comments
I am not sure if something like this already exists, but you could implement your own extension method similar to:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
1
@Groo I added more details to the answer because it seemsunmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected byMakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false whent.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)
– Reza Aghaei
Jan 1 at 14:21
|
show 2 more comments
I am not sure if something like this already exists, but you could implement your own extension method similar to:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}
I am not sure if something like this already exists, but you could implement your own extension method similar to:
public static bool IsUnmanaged(this Type type)
{
// primitive, pointer or enum -> true
if (type.IsPrimitive || type.IsPointer || type.IsEnum)
return true;
// not a struct -> false
if (!type.IsValueType)
return false;
// otherwise check recursively
return type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
(update) For completeness, since recursion will be slow for structs with many nested members, the function can be made faster by caching the results:
private static readonly ConcurrentDictionary<Type, bool> _memoized =
new ConcurrentDictionary<Type, bool>();
public static bool IsUnmanaged(this Type type)
{
bool answer;
// check if we already know the answer
if (!_memoized.TryGetValue(type, out answer))
{
if (!type.IsValueType)
{
// not a struct -> false
answer = false;
}
else if (type.IsPrimitive || type.IsPointer || type.IsEnum)
{
// primitive, pointer or enum -> true
answer = true;
}
else
{
// otherwise check recursively
answer = type
.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
.All(f => IsUnmanaged(f.FieldType));
}
_memoized[type] = answer;
}
return answer;
}
edited Dec 29 '18 at 13:45
answered Dec 29 '18 at 11:47
GrooGroo
35.3k1484158
35.3k1484158
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
1
@Groo I added more details to the answer because it seemsunmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected byMakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false whent.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)
– Reza Aghaei
Jan 1 at 14:21
|
show 2 more comments
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
1
@Groo I added more details to the answer because it seemsunmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected byMakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false whent.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)
– Reza Aghaei
Jan 1 at 14:21
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
Thanks for the answer. I chose the other one, as while I think this one is prettier, it is much slower (my test got it as 10-20x slower), and it only gets slower with larger objects.
– John
Dec 29 '18 at 12:23
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: hi, yes, the recursion if probably a killer here. I would assume that a cached/memoized version would be faster than the accepted one (i.e. one that uses a dictionary to store known results), especially since Reza's answer uses reflection (which is usually slow) and exceptions (which are slow -- although only if they are thrown).
– Groo
Dec 29 '18 at 13:31
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
@John: I've added the updated method, just to clarify what I meant. It should be as fast as the accepted answer, but it will use a bit more memory for the duration of the program (since the dictionary is static). I have used a ConcurrentDictionary to make the method thread safe, but if you know that this will be used from a single thread it can be made even faster using a plain dictionary. Of course, the accepted answer can use the same tactic to get the answer faster, if it's shown that it's needed. :)
– Groo
Dec 29 '18 at 14:05
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
this is not an O(1) algorithm, whereas the other is. This is, i think, O(n), as you need to check everything
– John
Dec 29 '18 at 14:07
1
1
@Groo I added more details to the answer because it seems
unmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected by MakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false when t.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)– Reza Aghaei
Jan 1 at 14:21
@Groo I added more details to the answer because it seems
unmanaged
constraint is just supported by C# compiler not the run-time, so despite all other constraints, it's not respected by MakeGenericType
method. So using a method like what you also have is an option (which is not perfect, because of exceptional case that I mentioned in my answer). And by the way, your code needs small fix, the method should return false when t.IsGenericType
, it's because of a limitation in the current version of language. Anyway, you have my vote :)– Reza Aghaei
Jan 1 at 14:21
|
show 2 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53968920%2fhow-do-i-check-if-a-type-fits-the-unmanaged-constraint-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
That's a type constraint for a generic. I'm asking for a given type
T
, at runtime, how can I check if it is unmanaged or not?– John
Dec 29 '18 at 11:04