-
Notifications
You must be signed in to change notification settings - Fork 8.1k
(#12430) Improve detection of mutable value types #12495
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2030,36 +2030,39 @@ private static object NullRule(CallSite site, object obj) | |
|
|
||
vexx32 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Show resolved
Hide resolved
vexx32 marked this conversation as resolved.
Show resolved
Hide resolved
daxian-dbw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| internal static bool IsValueTypeMutable(Type type) | ||
| { | ||
| if (type.IsPrimitive || type.IsEnum) | ||
| // First, check for enums/primitives and compiler-defined attributes. | ||
| if (type.IsPrimitive | ||
| || type.IsEnum | ||
| || type.IsDefined(typeof(System.Runtime.CompilerServices.IsReadOnlyAttribute), inherit: false)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // If there are any fields, the type is mutable. | ||
| if (type.GetFields(BindingFlags.Public | BindingFlags.Instance).Length > 0) | ||
| // If the builtin attribute is not present, check for a custom attribute from by the compiler. If the | ||
| // library targets netstandard2.0, the compiler can't be sure the attribute will be provided by the runtime, | ||
| // and defines its own attribute of the same name during compilation. To account for this, we must check the | ||
| // type by name, not by reference. | ||
| foreach (object attribute in type.GetCustomAttributes(inherit: false)) | ||
| { | ||
| return true; | ||
| if (attribute.GetType().FullName.Equals( | ||
| "System.Runtime.CompilerServices.IsReadOnlyAttribute", | ||
| StringComparison.Ordinal)) | ||
|
Comment on lines
+2047
to
+2049
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the reason for needing to do a type name comparison rather than a simple type comparison here?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@rjmholt if you target
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok got it -- might be worth a comment so that someone doesn't "optimise" it
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I already added comments for this just above (2040-2043) - should I move those closer to this line/reword them a bit?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I would just add something like "so we must check for the type by name rather than by reference" after the bit about the compiler |
||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| // If there are any properties with setters, the type is mutable. | ||
| var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); | ||
| for (int index = 0; index < properties.Length; index++) | ||
| // Fallback: check all fields (public + private) to verify whether they're all readonly. | ||
| // If any field is not readonly, the value type is potentially mutable. | ||
| foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) | ||
| { | ||
| var property = properties[index]; | ||
| if (property.CanWrite) | ||
| if (!field.IsInitOnly) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| // If there are any methods other than the property getters, the type might | ||
| // be mutable, so assume the type is mutable. | ||
| var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); | ||
| if (methods.Length != properties.Length) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // If all fields are init-only (read-only), then the value type is immutable. | ||
| return false; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.