Using legacy extension methods from a third-party library

This question is not about a method that I can mark with [System.Obsolete]. The method that I want to ignore is in the dll, I have no control.

I am using a third-party library that contains an extension method for objects. This leads to confusion and may cause problems in the future. Is there a way to mark this extension method (or all extension methods from a specific dll) as obsolete from the outside or prevent this extension method from appearing in intellisense. Problematic Method:

public static class ExtensionMethods { public static bool IsNumeric(this object obj) { if (obj == null) return false; return obj.GetType().IsPrimitive || obj is double || (obj is Decimal || obj is DateTime) || obj is TimeSpan; } } 
+5
source share
2 answers

The best way to handle this is to use Roslyn and create your own code analyzer or use an existing tool like FxCop.

However, for this I found a very not elegant way.

In your project, you can create a class with the same name as the reference class in the same namespace using the same method. Now mark your method as deprecated.

The following code example has a link to a library with the ExtensionMethods class, which is defined in the External namespace. On the line marked with a comment (*) , where the method is invoked using the syntax for invoking the static method, the compiler warns you that the ExtensionMethods type conflicts with the imported type. It also tells you that the method is deprecated (since you are obscured by the imported type, it sees your definition). Therefore, when you call a method, your code will work. In the line marked with a comment (**) , where the method is called using the syntax for invoking the extension method, the compiler says that the call is ambiguous and the code will not compile. The only workaround I know is to include this call in a string (*) , which will lead to an outdated warning.

With this solution, you can call other extension methods from a reference type if you use the extension method syntax, if you do not have the same method defined in your class.

 using System; using External; namespace Internal { class Program { static void Main(string[] args) { ExtensionMethods.IsNumeric(new object()); // (*) new object().IsNumeric(); // (**) } } } namespace External { public static class ExtensionMethods { [Obsolete] public static bool IsNumeric(this object o) { if (obj == null) return false; return obj.GetType().IsPrimitive || obj is double || (obj is Decimal || obj is DateTime) || obj is TimeSpan; } } } 
+4
source

You can do this with the Roslyn Code Analyzer. The following code will create a DiagnosticAnalyzer , which will give a warning to the compiler if String.EndsWith() .

 [DiagnosticAnalyzer(LanguageNames.CSharp)] public class ForbiddenMethodsAnalyzer : DiagnosticAnalyzer { private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor("Forbidden", "Don't use this method!", "Use of the '{0}' method is not allowed", "Forbidden.Stuff", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: "This method is forbidden"); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } } public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression); } private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context) { var invocationExpression = (InvocationExpressionSyntax)context.Node; var memberAccessExpression = invocationExpression.Expression as MemberAccessExpressionSyntax; if (memberAccessExpression?.Name.ToString() == "EndsWith") { var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccessExpression).Symbol as IMethodSymbol; var containingType = memberSymbol.ContainingType; if (containingType.ContainingNamespace.Name == "System" && containingType.Name == "String") { var diagnostic = Diagnostic.Create(Rule, invocationExpression.GetLocation(), memberAccessExpression.ToString()); context.ReportDiagnostic(diagnostic); } } } } 

Warning clues Error warning

There are 3 options for using the analyzer:

  • Add the DiagnosticAnalyzer code directly to your project. It will only apply to this decision.
  • Create a class library with DiagnosticAnalyzer in it and distribute it as a Nuget package. It will only apply to solutions using the package.
  • Compile the full VSIX extension containing the class. The analyzer will work with any solution you download.

This is the first project I have used that uses the Roslyn code analysis functionality, so unfortunately I do not understand everything that happens here. I started with the default analyzer template and tried various methods, went through the code and looked at the variables with the clock windows until I found the information needed for this function.

The main process is to register the SyntaxNode Analysis function, filtered in expressions that invoke the method. Inside this method, I check to see if the Name the MemberAccessExpressionSyntax "EndsWith" is MemberAccessExpressionSyntax checked. If so, I get a ContainingType that this method is included, and check if it is in the String class in the System namespace. If so, I create an instance of Diagnostic from the DiagnosticDescriptor to tell the IDE where the problem is and what part of the problem it represents (warning in this case, I could make it a complete mistake if I wanted to, which would prevent code compilation ) It is also possible to present the user with various parameters in order to automatically correct the error, but I have not yet studied it.

A lot of information from this tutorial , as well as a lot of trial and error.

+4
source

Source: https://habr.com/ru/post/1270590/


All Articles