0

The "unmanaged" generic type constraint was added in c# 7.3, but I'm curious why a corresponding "managed" type constraint was not added at the same time (or since)?

The unmanaged constraint comes pretty close to being a constraint for primitive types, but will also constrain structs that do not refer to any managed types. That's fine, but I would like to write a constraint that is just the opposite. My immediate use case is to write extension methods for IDictionary<Object, Object> where the signatures look like:

public static void Add(this IDictionary<Object, Object> map, TValue value) where TValue : managed

and

public static bool TryGetValue(this IDictionary<Object, Object> map, out TValue value) where TValue : managed

Obviously the implementations would add and get values from the dictionary using the key: typeof(TValue).

Having such methods make sense (to me) when you will have objects of different types uniquely in the dictionary, usually user defined classes or structs, where the structs would need to contain some managed type references. But such methods wouldn't make so much sense for storing value by unique primitive types, so I would like to exclude such values from being mapped to the methods.

I understand there are other solutions (such as using KeyedByTypeCollection) to address the use case. Please don't answer the question by pointing to another solution to the use case. I'm just providing it as an example. I believe there must be many other use cases for have a managed constraint (probably as many as there are for the unmanaged case), and frankly I'm a little surprised that no one seems to have asked about this previously (at least I can't find anything about it).

Paul
  • 17
  • 1
  • 4
  • I'd strongly recommend reading https://stackoverflow.com/a/8673015/477420 by Eric Lippert:" Features are unimplemented by default; C# does not have that feature because no one designed, implemented and shipped the feature to customers." – Alexei Levenkov Mar 12 '23 at 22:05
  • Fair enough; I guess the form I put my question was going to elicit this answer. But I am interested in seeing what people think about this missing feature. Again, I wonder why I found no discussion anywhere about it, and so am asking the question myself, so that others can find this discussion if they have this question. So let me ask my question this way, "why has no one asked for this feature already"? Before I open a request for it, I would want to know that other people might find value in it. If it's simply because there are very few uses case for it, fine. But I am curious. – Paul Mar 13 '23 at 01:12

1 Answers1

1

I think there's no value in what you're looking for. You can use a where TValue : class constraint if you want a reference type only. Reference types are always managed.

However, if you use a value type constraint (e.g. with where TValue : struct), this includes all unmanaged types, since there are operations that are allowed on unmanaged types (e.g. blitting), but not on general structs (structs with references). But all operations that are allowed on struct types are allowed on blittable types as well. Therefore, there's no reason to have a generic constraint for only managed types.

PMF
  • 14,535
  • 3
  • 23
  • 49
  • This answer doesn't seem quite correct to me? A struct with reference types is not a class, therefore the "class" constraint won't apply. For the rest I think you are saying that a struct constraint will apply to structs, whether blittable or general, which is irrelevant I think, to my question? I would like a way to constrain any types that are classes or general structs, but not blittable structs. If you think there's no use case for that, fine. But I don't think you've answered my question, nor given a reason why it's not a possible use case (which I think you were aiming to do)? – Paul Mar 13 '23 at 00:56
  • The reason is that there isn't a clear use case. Its just another case of the minus 100 points issue: https://devblogs.microsoft.com/oldnewthing/20090928-00/?p=16573 Blittable types are a useful constraint because that allows you to build generic marshaling code and things that build on that. Without a clear operation that can be done only on non-blitable structs, its unclear who you could code that would work on non-blitable structs but not blitable. – user1937198 Mar 13 '23 at 01:41
  • @Paul It's a bit difficult to express, but I think you got the point. If a generic class/method works with structs with reference fields, it also works with blittable structs, just not the other way round. Type constraints are there to specify what operations are allowed on a template argument, not what operations are _not_ allowed. Note that adding a constraint _adds_ operations you can do on instances of T. – PMF Mar 13 '23 at 07:14
  • I certainly see why the unmanaged constraint - because it's useful in marshaling scenarios, etc. Why in this case I thought the opposite would be is this: I'm given a IDictionary that I want to use like IServiceProvider, and I'm given a value that is a general struct to store in it (it just happened that way). It doesn't make sense then to also use this dictionary to store primitive values with one value of type int, another value of type boolen ... so I wanted to constrain my ext methods to prevent storing primitives. But I guess I'll just have to go without that. Thanks! – Paul Mar 14 '23 at 01:31
  • @Paul It either still makes sense in that use case to allow blittable structs, or you want to forbid all structs. The blittableness of a struct is not really relivant in that scenario. What you want is to forbid primitive (And arguably primitive like) data structures, which isn't really a responsibility of the type system. After all, why should your API refuse to store int or char but allow storing a string? – user1937198 Mar 14 '23 at 21:04
  • @user1937198 You're right, for my use case if I want to forbid primitives types I would also want to forbid the string type, and a "managed" constraint (that only forbids blittable types and structs) wouldn't do that. Even though it's clear that I would like to forbid those types, its not so clear for general structs that we want to allow any and all (some we wouldn't). At best if I were able to apply a managed constraint that would only forbid the obviously inappropriate but not the not so obvious. So I'm good with allowing all types. At least then there's no ambiguity. Thanks again. – Paul Mar 15 '23 at 03:13