Как я могу проверить типы, передаваемые методу во время разработки или компиляции?C#

Место общения программистов C#
Ответить
Anonymous
 Как я могу проверить типы, передаваемые методу во время разработки или компиляции?

Сообщение Anonymous »

Я нахожусь в ситуации, когда существует множество сгенерированных типов из разных доменов/проектов/систем, но между ними много совпадений.
В прошлом я использовал такие вещи, как Automapper, чтобы обеспечить некоторую безопасность при преобразовании объектов между типами и доказательстве правильности.
В этом случае мне бы очень хотелось иметь что-то вроде утиной типизации.

У меня есть представление о том, какими должны быть некоторые движущиеся части, но мне сложно собрать их воедино.
  • Создайте пакет nuget с помощью одного метода Convert. Сделайте фактическую реализацию переопределяемой, но рассматривайте это как отправную точку для анализа утиной типизации.
    1b. Возможно, пометьте метод аннотацией, чтобы фильтровать его позже во время анализа кода.
  • Напишите анализатор roslyn, который сканирует использование этой конкретной функции (во время разработки или компиляции). Когда вызовы найдены, извлеките переданные общие типы и запустите некоторый блок кода, чтобы убедиться, что TSource и TTarget эквивалентны, рекурсивно по свойствам.
    Возможно, используйте что-то вроде DeepEqual
    2b. Возможно, реализуйте нечто большее, чем просто Convert, например ConvertSubset/ConvertDown и ConvertSuperset/ConvertUp.
  • В идеале это может быть единый пакет nuget с библиотекой DuckType Convert и анализатором roslyn, и когда пользователь его загрузит, он включит анализатор... Я пока не знаю, правда ли это.
Я изучил страницы анализаторов roslyn на сайте Learn.microsoft.com 1 2 3
и блог Meziantou 3 4
, чтобы начать работу с анализаторами Roslyn.
Я не понимаю, как конкретно добавить проверку к вызовам определенной функции.
Интересно, есть ли что-нибудь подобное? атрибута stylecop или resharper, который может позволить мне проверять время индивидуальной разработки. Я искал, но не нашел ничего подобного.
Я рассматривал возможность украшения моего метода Convert пользовательским атрибутом (например, DuckTypesEqualAttribute).
Я вижу, что на странице Learn.microsoft.com, посвященной дженерикам и атрибутам, есть некоторая информация, но ничего не кажется очень полезным.
Я пытаюсь реорганизовать метод Convert в обобщенный класс и создать DuckTypeFactory, которая делегирует генерацию правильного типизированного класса и вызывает Convert.
Я надеялся, что атрибут сможет каким-то образом захватить (во время разработки или компиляции) аргументы универсального типа, и я просканировал бы их в анализаторе roslyn.
Здесь не повезло. Каждый раз, когда я пытаюсь иметь открытые универсальные типы или ссылаться на универсальные типы в свойствах атрибута, возникают ошибки.
В конце страницы говорится:

Начиная с C# 11, универсальный тип может наследовать от Attribute
Я пробовал это с обобщенным классом, и это также не удается с CS8968 «Аргумент типа атрибута не может использовать параметры типа»

Итак, я вернулся к созданию простого атрибута в качестве маркера для метода, а затем попросил анализатор roslyn найти каждое место, где вызывается метод.
Это неудобно, у меня пока ничего не работает.
Мне бы хотелось получить какие-нибудь рекомендации или ссылки на код, где люди делали подобные вещи.
Или предложения в другом направлении, чем анализатор roslyn, если вы знаете что-то еще подходит.
Спасибо!
пример кода — библиотека DuckTyping:

Код: Выделить всё

using System;

namespace DuckTyping
{
//marker attributes for roslyn analyzer to find methods
class DuckTypeEqualAttribute: Attribute {}
class DuckTypeSubsetAttribute: Attribute {}
class DuckTypeSupersetAttribute: Attribute {}

public class DuckTyping
{
/// 
/// static Converter function. Override with desired conversion function.  Recommend NewtonsoftJson Convert.
/// 
public static Func Converter { get; set; } = (obj, t1, t2) => System.Convert.ChangeType(obj, t2);//avoid an explicit reference to newtonsoft json, user to override impl at startup

[DuckTypeEqual]
public static TDest Convert(TSource obj) => (TDest) Converter(obj, typeof(TSource), typeof(TDest));

[DuckTypeSubset]
public static TDest ConvertSubset(TSource obj) => (TDest) Converter(obj, typeof(TSource), typeof(TDest));

[DuckTypeSuperset]
public static TDest ConvertSuperset(TSource obj) => (TDest) Converter(obj, typeof(TSource), typeof(TDest));
}
}
Код анализатора Roslyn... Я застрял :-(

Код: Выделить всё

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Operations;

namespace DuckTyping
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class DuckTypingAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "DuckTyping";

private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
private const string Category = "Type Checking";

private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);

public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }

public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();

context.RegisterSymbolAction(handler, SymbolKind.Method);
context.RegisterOperationAction(handler, OperationKind.ExpressionStatement);
}

private static void handler(SymbolAnalysisContext ctx)
{
var methodSymbol = (IMethodSymbol)ctx.Symbol;
if (false) // ??? somehow check if the method called is DuckTyping.Convert
{
// ??? somehow extract the generic types in the call

//use DeepEqual to verify equal types, if not equal, report
ctx.ReportDiagnostic(Diagnostic.Create(Rule, methodSymbol.Locations[0], methodSymbol.Name));
}
}

private static void handler(OperationAnalysisContext ctx)
{
var expressionStatement = (IExpressionStatementOperation)ctx.Operation;
if (false) // ??? somehow check if the expression statement is calling DuckTyping.Convert
{
// ??? somehow extract the generic types in the call

//use DeepEqual to verify equal types, if not equal, report
ctx.ReportDiagnostic(Diagnostic.Create(Rule, expressionStatement.Syntax.GetLocation(), expressionStatement.Syntax.GetText()));
}
}
}
}

редактировать:
Я нахожу направление, используя Logging.Analyzer asp.net в качестве справочного
источника


Подробнее здесь: https://stackoverflow.com/questions/785 ... mpile-time
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»