How do I check if a type fits the unmanaged constraint in C#?












6















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










share|improve this question

























  • 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
















6















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










share|improve this question

























  • 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














6












6








6


1






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










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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

















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












2 Answers
2






active

oldest

votes


















4














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 or UIntPtr.

  • 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






share|improve this answer


























  • 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













  • 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











  • 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



















3














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;
}





share|improve this 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 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











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
});


}
});














draft saved

draft discarded


















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









4














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 or UIntPtr.

  • 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






share|improve this answer


























  • 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













  • 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











  • 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
















4














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 or UIntPtr.

  • 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






share|improve this answer


























  • 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













  • 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











  • 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














4












4








4







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 or UIntPtr.

  • 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






share|improve this answer















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 or UIntPtr.

  • 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







share|improve this answer














share|improve this answer



share|improve this answer








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 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











  • @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



















  • 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













  • 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











  • 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

















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













3














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;
}





share|improve this 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 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
















3














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;
}





share|improve this 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 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














3












3








3







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;
}





share|improve this 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;
}






share|improve this answer














share|improve this answer



share|improve this 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 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



















  • 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 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

















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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Monofisismo

Angular Downloading a file using contenturl with Basic Authentication

Olmecas