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
IsInitOnly boolean property for PropertyDefinition in SDK #80205
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
See #34978 and especially #43088 (comment) for sample code that detects Alternatively, your arch tests could perhaps use IMethodSymbol.IsInitOnly in the Roslyn API. |
yeah, I saw this comment before the opening this issue. I think that the suggested solution is a crutch. I don't want use that in my tests |
May you elaborate as to why it's a crutch (there are 3 suggested solutions) and why you want that property in particular? Probably we will move this elsewhere, maybe the Runtime, doesn't seem like it's part of the SDK. |
Tagging subscribers to this area: @dotnet/area-system-componentmodel Issue DetailsI am trying to check that my property has it would be nice to have the Below I posted the IsInitOnly property from FieldDefinition
By using the IsInitOnly prop I can validate in my arch tests that all properties in Domain models are init-only
|
Do you mean Also the auto-labeler moved this to the System.ComponentModel namespace; I assume it was meant for System.Reflection. |
Tagging subscribers to this area: @dotnet/area-system-reflection Issue DetailsI am trying to check that my property has it would be nice to have the Below I posted the IsInitOnly property from FieldDefinition
By using the IsInitOnly prop I can validate in my arch tests that all properties in Domain models are init-only
|
I have a property, not field |
@nagilson well, do you suggest me use enumerator for every property in my type by checking existing of
correct? if yes, you really think that it's not crutch?) |
My point is that "PropertyDefinition" is not a type in .NET reflection. -- it's called "PropertyInfo". Just making sure we're talking about the same thing (or not). Assuming we're talking about "PropertyInfo" then the ask here is to add: namespace System.Reflection
{
public class PropertyInfo
{
+ public bool IsExternalInit { get; } // not "IsInitOnly" based on discussion in issue #34978
} |
The workaround is to add your own extensions method; I do however think that reflection should be updated to expose this directly. Sample workaround: internal class Program
{
static void Main(string[] args)
{
PropertyInfo propertyInfo = typeof(Person_InitExample).GetProperty("YearOfBirth")!;
Console.WriteLine($"IsInit: {propertyInfo.IsExternalEmit()}");
}
}
internal static class ReflectionExtensions
{
public static bool IsExternalEmit(this PropertyInfo propertyInfo)
{
MethodInfo? setter = propertyInfo.GetSetMethod();
if (setter is not null)
{
foreach (Type modreq in setter.ReturnParameter.GetRequiredCustomModifiers())
{
if (modreq == typeof(System.Runtime.CompilerServices.IsExternalInit))
{
return true;
}
}
}
return false;
}
}
class Person_InitExample
{
private int _yearOfBirth;
public int YearOfBirth
{
get { return _yearOfBirth; }
init { _yearOfBirth = value; }
}
} |
oops, I meant |
Moving to future; the ask for the "IsInitOnly" is valid and useful. |
namespace System.Reflection;
public partial class PropertyInfo
{
public bool IsInitOnly { get; }
} |
IMO This is the wrong approach. Whether a setter is This should instead eiher be something like: namespace System.Reflection;
public abstract class PropertyInfo : MemberInfo
{
public virtual MethodInfo? GetMethod { get; }
public virtual MethodInfo? SetMethod { get; }
+ public virtual bool SetMethodIsInitOnly { get; } // or IsSetAccessorInitOnly, or IsSetterInitOnly, etc...
} or namespace System.Reflection;
public abstract class PropertyInfo : MemberInfo
{
public abstract bool CanRead { get; }
public abstract bool CanWrite { get; }
// if true, CanWrite can also return true to maintain backwards compatibility, or they can be separate
// and CanWrite could now return false and only CanInit would return true
+ public virtual bool CanInit { get; }
} or namespace System.Reflection;
public abstract class MethodInfo : MethodBase
{
+ public virtual bool IsGetter { get; } // or IsGet or IsGetMethod
+ public virtual bool IsSetter { get; } // or IsSet or IsSetMethod
+ public virtual bool IsAdder { get; } // or IsAdd or IsAddMethod
+ public virtual bool IsRemover { get; } // or IsRemove or IsRemoveMethod
// same compatibility concern as above
+ public virtual bool IsInitter { get; } // or IsInit or IsInitMethod
} or namespace System.Reflection;
+public enum AccessorKind
+{
+ Get,
+ Set,
+ Init,
+ Add,
+ Remove,
+}
public abstract class MethodInfo : MethodBase
{
+ public virtual AccessorKind? AccessorKind { get; }
} or maybe even this, although the same compatibility applies here as well (whether CanWrite would also return true and SetMethod would return the method like today to maintain backwards compatibility, or they can be separate and only CanInit would return true and InitMethod would return the method) namespace System.Reflection;
public abstract class PropertyInfo : MemberInfo
{
public abstract bool CanRead { get; }
public abstract bool CanWrite { get; }
+ public virtual bool CanInit { get; }
public virtual MethodInfo? GetMethod { get; }
public virtual MethodInfo? SetMethod { get; }
+ public virtual MethodInfo? InitMethod { get; }
} |
There is no problem with making them piece-meal. Even C# added all these features piece by piece with every release. Whether a property or field is
|
Notably, with public abstract class FieldInfo : MemberInfo
{
+ public virtual bool IsRequired { get; }
}
public abstract class PropertyInfo : MemberInfo
{
+ public virtual bool IsRequired { get; }
} This seems much more straightforward (although it gets a bit complicated with constructors that set all required fields... but I think checking whether the property was declared as |
cc @jaredpar I think the C# folk should also have a say or add some input here since this is about C# features. |
Regarding whether the property should support externally-defined polyfilled modreqs rather than just the builtin corelib ones - YES it should, because the compiler does as well. Many libraries declare their own |
This is true but at the same time
I would recommend against this pattern. Yes that is the canonical |
Right. I would be OK with a property like |
Exactly. That's a really, really bad pattern that would break half the world. The language feature isn't defined by whether the modreq comes from mscorlib. Just this fact is an argument in favor of the API existing (and doing it correctly), since many people who will implement it manually will likely do it the wrong way. |
That said, a feature like this: namespace System.Reflection;
+public enum AccessorKind
+{
+ Get,
+ Set,
+ Init,
+ Add,
+ Remove,
+}
public abstract class MethodInfo : MethodBase
{
+ public virtual AccessorKind? AccessorKind { get; }
+ public virtual MemberInfo? AccessorMember { get; }
// Or maybe:
+ public virtual MemberInfo? Parent { get; } // or DeclaringMember
// where Parent could be a property of an property accessor, an event of an event accessor,
// a parent method of a local function, or regular parent type of a regular method.
// Or even better, a MethodKind like Roslyn has that would allow checking not only if it's an accessor,
// but also a local function, operator, lambda, etc. Roslyn has this as `IMethodSymbol.MethodKind`.
} would be really useful anyway as it would allow checking whether a method is an accessor when all you have is |
This Moreover, ECMA-335 allows the same method to be an accessor of multiple properties and/or events, if you don't care about CLS compliance. So MethodInfo.AccessorKind and MethodInfo.Parent would have to pick one, ugh. |
@KalleOlaviNiemitalo That was just an example. I'm not too familiar with the runtime itself - it could of course be changed to be compliant. Although if we want this to have semantics of the runtime and not C#, then an |
FWIW, in Roslyn, whether a property has an |
As an alternative in case the BCL doesn't want to expose C# specific concepts in reflection... Maybe it should be made easy to get Roslyn's This would have the advantage that it could work for VB-specific concepts as well. (And IMO, |
API Proposal
namespace System.Reflection; public class PropertyInfo { + public bool IsInitOnly { get; } }
Note "IsInitOnly" is used since that is similar to FieldInfo's. However, "IsExternalInit" is an alternative based on #34978 and #43088 (comment).
Original description
I am trying to check that my property has
init
-only setter, e.g.public int Foo {get; init;}
it would be nice to have the
IsInitOnly
property in PropertyDefinition similar to which inFieldDefinition
class from Mono.CecilBelow I posted the IsInitOnly property from FieldDefinition
By using the IsInitOnly prop I can validate in my arch tests that all properties in Domain models are init-only
The text was updated successfully, but these errors were encountered: