-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Add Type.IsReferenceType
#90993
Comments
Tagging subscribers to this area: @dotnet/area-system-reflection Issue DetailsBackground and motivation
API Proposal namespace System;
public abstract partial class Type
{
// Existing APIs for reference:
public bool IsValueType { get; }
protected virtual bool IsValueTypeImpl();
// Proposed APIs:
+ public bool IsReferenceType { get; }
+ protected virtual bool IsReferenceTypeImpl();
} API Usageif (type.IsReferenceType)
{
// do something
} Alternative DesignsNo response RisksNo response
|
ECMA-335 states that at the highest level there are only value types and reference types, so For unconstrained generic parameters, yes that is an edge case and I don't think we want to add |
Setting to "future" for now; I believe we'll end up closing this. |
It's not just generics, there are also by-ref types. It's not that easy to check whether something is a regular reference type. I think it should be easier. Why not add the property, it feels natural to have it next to the existing |
I believe it's better to collect concrete examples with possible workarounds to see if there are inconsistencies that really get into the eye or workarounds that are completely non intuitive or something like that. Otherwise this is just easily done via extensions method in your own codebase. |
Could you please share example of existing code in this repos or elsewhere on github that would benefit from this API? I would not be opposed to introducing a convenience API like this if we have a proof of its usefulness. There are multiple conflicting definitions of "reference type". The C# definition is different from ECMA-335 definition. It would be best for the proposal to show implementation of the API using existing properties. It would clarify its exact behavior and it is something that we would need for the baseline
Nit: I do not think that this would need to through public property + protected implementation split. This split is historic artifact, we have not done it for newer System.Type APIs. |
I don't know how it should be implemented. I don't know all the possible types that can occur and all the derived classes etc. That's the problem and that's why the API is needed - because it's not obvious or trivial to do this correctly, because of all the possible kinds of types that exist. |
An implementation that matches ECMA-335 definition of a reference type would be |
A by-ref parameter is considered a "reference type" in terms of ECMA-335 meaning, for example, that it will be tracked by the runtime for GC (at least if not a simple blittable value type). So treating "IsReferenceType == false" for by-ref parameters probably wouldn't pass review. |
That's not good enough. If a type parameter is constrained to be This is why I'm proposing the API. It's easy to get this wrong if you do it manually. |
@steveharter Fair enough. I would expect that to return false, but if that's what the spec says, then so be it. |
I didn't expect so much pushback. To me it feels like a natural companion to the existing |
I see two concerns with this proposal (reiterating #90993 (comment)):
If you can address these two concerns, the proposal will have much better chance.
There was no ambiguity how |
In my case I needed it to determine whether a public static bool IsNullable(this Type type)
{
return type.IsReferenceType || type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
I think the only question was regarding by-ref types, and @steveharter answered that. It would be well defined for generic type parameters - it should return true if the type parameter has the |
To demonstrate general usefulness of an API proposal, it is best to share pointers to somebody else's existing code in this repo or elsewhere on github that would benefit from the API.
This behavior is not necessarily a good prior art. No other For example, consider this: using System.Reflection;
using System.Reflection.Emit;
var ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.Run);
var mb = ab.DefineDynamicModule("MyModule");
var tb = mb.DefineType("MyType");
var gb = tb.DefineGenericParameters("T")[0];
gb.SetBaseTypeConstraint(typeof(ValueType));
var genericType = tb.CreateType();
var genericParameter = genericType.GetGenericArguments()[0];
// This prints `true` (not quite what one would expect) ...
Console.WriteLine(genericParameter.IsValueType);
var instantiatedGenericType = genericType.MakeGenericType(typeof(ValueType));
var instantiatedGenericParameter = instantiatedGenericType.GetGenericArguments()[0];
// ... but this prints false.
Console.WriteLine(instantiatedGenericParameter.IsValueType); |
Does ECMA not say anything about pointer types? Because those are neither reference nor value types, and Related: @Neme12 Remember that pointer types can also be assigned |
This is true for C# definition of reference types. ECMA 335 has different definition of reference types that considers pointer type to be a reference type:
Also, ECMA 335 has second different definition of a reference type for the purposes of assignment compatibility:
|
Thanks, I'll make sure that the |
This is the existing code I have to write: public static bool IsReferenceType(this Type type)
{
if (type.IsGenericParameter)
{
var attributes = type.GenericParameterAttributes;
if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
return true;
var constraints = type.GetGenericParameterConstraints();
if (constraints.Any(type => type != typeof(ValueType) && !type.IsInterface && type.IsReferenceType()))
return true;
return false;
}
return !type.IsValueType;
}
I'm not too worried about that because people don't write IL in practice. Also, couldn't this behavior be fixed? It seems like a corner case that wouldn't actually break anyone in practice if it got changed. ... |
I don't think Also, if we did this, we would need to consider whether we should also update the semantics of @Neme12 can you elaborate on your reflection usage of it - are you trying to invoke a member and\or close an open generic parameter, generating code from reflection metadata, or something else? Some misc searches for ".GetGenericParameterConstraints(" didn't yield anything. |
Based on my previous reply, an alternative solution then would be to update IsValueType, IsClass and IsInterface so that they respect constraints. |
This issue has been marked |
This issue has been automatically marked |
This issue will now be closed since it had been marked |
Background and motivation
Type
already has theIsValueType
property, but there's noIsReferenceType
property. This is necessary because it's not equivalent to just!type.IsValueType
, and that's because there are types that are neither value or reference types, such as unconstrained generic parameters.API Proposal
API Usage
Alternative Designs
No response
Risks
No response
The text was updated successfully, but these errors were encountered: