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
Make System.Security.Cryptography.Oid write-once (initializable read-only) #2043
Comments
I would like this, I wonder if that means it would be feasible to implement equality members on |
What would the equality operators do on an uninitialized instance? |
I thought about going further and suggesting IEquatable; but then we'd need to be ctor-only. I started at that position, then saw non-zero set calls in telemetry, and softened my stance. I'm personally content to go whole-hog and make the setters be throw-if-not-my-value (or just straight throw, but that sometimes leads to bad debugger experiences). We'd also need to decide if equality was only on Value (probably what someone wanted) or on both properties (differently makes sense). Oid normalized = new Oid(OidValues.RsaEncryption);
Oid valueValue = new Oid(OidValues.RsaEncryption, OidValues.RsaEncryption);
Oid legalButWeird = new Oid(OidValues.RsaEncryption, "par-tay!");
bool decide1 = normalized.Equals(valueValue);
bool decide2 = normalized.Equals(legalButWeird); |
Well, I can understand that is an even bigger break, so I’m happy regardless. Less defensive copies would be good enough, but I’ve always though Oid should be a “typed string” similar to HashAlgorithmName. I’ll admit the friendly name never made too much sense to me, secondary display text if anything. I’d be in favor of the Oid ignoring it for equality purposes. |
public partial class Oid
{
public string Value
{
get => _value;
set
{
if (_value != null && !_value.Equals(value))
throw new PlatformNotSupportedException(...);
_value = value;
}
}
public string FriendlyName
{
get => _friendlyName ??= LookupFriendlyName(_value);
set
{
if (_friendlyName != null && !_friendlyName.Equals(value))
throw new PlatformNotSupportedException(...);
_friendlyName = value;
}
}
} |
@bartonjs are you working on this? If not, mind if I do? General thought would be to 1. Make changes 2. follow up PRs to remove defensive copies where possible. |
It's currently like 6th on my todo list, so go for it. I agree with the approach of making the small PR first (just the new throw and tests verifying it), then followup PRs to stop being wasteful. (Be careful of the Pkcs library, since it ships netstandard, so it would probably want a helper method like internal static Oid CloneOid(Oid toClone)
{
Debug.Assert(toClone != null);
#if NETSTANDARD
return new Oid(toClone.Value, null);
#else
return toClone;
#endif
} ) |
@bartonjs can you please file a breaking change issue? https://github.com/dotnet/docs/issues/new?template=dotnet-breaking-change.md |
Breaking change doc PR is dotnet/docs#19680. |
The Oid class, reductio ad absurdum, is
There's a bit of "build FriendlyName for you" logic and some other lookup routines, but that's essentially what it is.
Because the properties are mutable, things like ECCurves.NamedCurves.get_nistP256() return a new Oid instance on every call; lest static state get corrupted.
This proposal suggests changing the properties to allow "assign-once" semantics. Building the property via an object initializer would still be permitted, but once the property gets a non-null value it cannot be changed.
Reductio ad absurdum implementation:
Telemetry shows very few callers of the setters, but not "zero".
Benefits:
The text was updated successfully, but these errors were encountered: