-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Please allow [assembly: TypeForwardedTo(typeof(T))] when T is [Obsolete] #61264
Comments
Obsolete(true) doesn't stop usage. It's easy to still use from things like your own obsolete scopes.
Then that's on them :-). You told them. They ignored (which is possible with error or warning). They get broken :-) |
Nothing will be 100%, I'm not under the impression that is something that can be achieved :) You can certainly access obsolete elements via reflection, and probably other ways. But, there are also ways I can defend against that, such as blocking the plugin, (if it's a new release), or even having an allow-list of plugins that are allowed to load the new assembly that hosts the obsolete types (that is, only specific old plugins can use it; all plugins load into ALCs now and I can allow/block assemblies, but not types).
Sure, of course. But I can't inspect every plugin that is released, and sometimes a plugin is released that does something bad and it doesn't get caught until years later. In the meantime, it becomes popular and people depend on it for their use of the app. Then, me breaking the plugin inflicts pain on users/customers, not the plugin author, who often has wandered somewhere else in life and isn't maintaining the plugin. I'm just looking for more tools to address the needs of refactoring and keeping the codebase clean, while maintaining compatibility and happy users. |
I've been doing a lot of cleanup and refactoring in my app's codebase (Paint.NET) over the last several months (well, slowly over years, rapidly over the last 6 months). It's approximately 600,000 lines of code and has acquired a lot of cruft. A lot of that cruft can be deleted, as it's internal stuff.
However, some of that cruft is/was used by plugins. Sometimes because it was an official API that I was providing, other times because it was something I neglected to mark as
internal
(there's a whole story there... 🤦♂️). I cannot / will not delete these classes because I take backwards compatibility very seriously. I'm not interested in breaking someone's workflow because their favorite plugin was using an API that I want to sweep away, sometimes just for aesthetic reasons; I don't want to make it my user's/customer's problem.[Obsolete("...", true)]
is a great tool for this.I'm now finding that certain types of refactoring/cleanup are hitting another wall: I can move types to lower-layer assemblies by using
[assembly: TypeForwardedTo(typeof(T))]
and this works great ...except for obsolete types (with theerror=true
flag), because it results in a compile-time error that cannot be suppressed. This prevents me from taking a bunch of old classes out of e.g.PaintDotNet.Effects.dll
and moving them all toPaintDotNet.Effects.Obsolete.dll
. I want to do this to prevent new plugins from using them, and also to sweep them out of the way entirely (no Intellisense, no docs, etc.). But, old plugins would still continue to function (an absolute requirement).In addition, the inability to use
TypeForwardedTo(typeof(T))
on an obsolete type prevents me from doing other types of cleanup, such as dropping assembly references. If I can't moveT
out of its assembly, because it's obsolete, then I cannot prune any assembly references thatT
requires.As an example, let's say that types
T1
andT2
are inAssembly1
. I want to makeT1
obsolete and move it intoAssembly1.Obsolete
. I also want to moveT2
intoAssembly2
, and not haveAssembly1
referenceAssembly2
at all (1Assembly1.Obsolete1, however, would referenceAssembly2
). Right now I can't do that, and it's causing some inflexibility in how I can refactor things.There are two workarounds that I can think of for this right now. The first is to inject the
[assembly: TypeForwardTo(...)]
attributes as some kind of post-build event, e.g. using Mono.Cecil. That's way overkill and I shouldn't have to do that. The other is to use[Obsolete("...", false)]
, but that doesn't solve the problem of preventing new plugins from using those types (plugin authors will do this, they don't care 🤣 You should see the stuff I've seen in plugins ... dreadful, awful stuff!)The text was updated successfully, but these errors were encountered: