Избавиться от предупреждений о конфликте аспектов между OnMethodBoundaryAspect и ILocationValidationAspect?

PostSharp версии 6.7.12 для инструментов и библиотек. У меня есть несколько пользовательских атрибутов:

[PSerializable]
public sealed class CheckInvariantAttribute : OnMethodBoundaryAspect
{

    // Snip - build-time logic here...

    public override void OnExit(MethodExecutionArgs args)
    {
        // Check stuff...
    }
}

[Serializable]
public sealed class NotDefaultAttribute : LocationContractAttribute,
    ILocationValidationAspect<Guid>,
    ILocationValidationAspect<DateTime>,
    IValidableAnnotation
{
    // Snip - build-time logic here...

    public Exception ValidateValue(
        DateTime value, 
        string locationName, 
        LocationKind locationKind, 
        LocationValidationContext contect)
    {
        // Snip, do stuff...
    }

    public Exception ValidateValue(
        Guid value, 
        string locationName, 
        LocationKind locationKind, 
        LocationValidationContext contect)
    {
        // Snip, do stuff...
    }
}

... и я также использую другой доступный атрибут контракта кода. Я применяю оба из них к одному и тому же методу:

[CheckInvariant]
public virtual void DoSomething(
    [NotNull] SomeObjectType inst,
    [NotDefault] DateTime someVal,
    [StrictlyPositive] Decimal someAmt)
{
        // Snip, do stuff...
}

Когда я это делаю, я получаю предупреждение во время компиляции, в котором говорится Conflicting aspects on "My.Namespace.MyClass.DoSomething( /* insert parameters here */ )": transformations "My.Namespace.NotDefaultAttribute: Validates the value passed to parameter 'someVal' and "My.Namespace.CheckInvariantAttribute: Wrapped by advice(s) OnExit" are not commutative, but they are not strongly ordered. Their order of execution is undeterministic.

Прежде всего, я ожидаю, что они должны быть детерминированными - один применяет аспект к параметру, а другой применяется при выходе из метода. Здесь естественный порядок. Кроме того, я пытался пометить их как коммуникативные, я пытался упорядочить их по роли или по приоритету, и во всех случаях потерпел неудачу. (Возможно, я сделал это неправильно.)

Как избавиться от этих предупреждений?

Вот результат сборки для этого примера местоположения:

1>C:\MyProject\SomeClass.cs(159,23,159,27): warning PS0114: Conflicting aspects on "My.Namespace.MyClass.DoSomething(SometObjectType, System.DateTime, System.Decimal)": transformations "My.Namespace.NotDefaultAttribute: Validates the value passed to parameter 'someVal'" and "My.Namespace.CheckInvariantAttribute: Wrapped by advice(s) OnExit" are not commutative, but they are not strongly ordered. Their order of execution is undeterministic.
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: Detail of dependencies for the previous warnings: 
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: My.Namespace.CheckInvariantAttribute: Marker BEFORE (54):
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    (no dependency)
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: PostSharp.Patterns.Contracts.NotNullAttribute: Validates the value passed to parameter 'inst':
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    Provide Role=Validation
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: My.Namespace.NotDefaultAttribute: Validates the value passed to parameter 'someVal':
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    Provide Role=Validation
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: My.Namespace.CheckInvariantAttribute: Wrapped by advice(s) OnExit:
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    Action=Order, Position=After, Condition = {equals "My.Namespace.CheckInvariantAttribute: Marker BEFORE (54)"}
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    Action=Order, Position=Before, Condition = {equals "My.Namespace.CheckInvariantAttribute: Marker AFTER (54)"}
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: PostSharp.Patterns.Contracts.StrictlyPositiveAttribute: Validates the value passed to parameter 'someAmt':
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    Provide Role=Validation
1>Namespace\MyClass.cs(159,23,159,27): message PS0124: My.Namespace.CheckInvariantAttribute: Marker AFTER (54):
1>Namespace\MyClass.cs(159,23,159,27): message PS0124:    (no dependency)
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Пока атрибут [NotDefault] применяется к параметру, фактическое преобразование применяется к телу метода. И это в основном то же преобразование OnMethodBoundary, что и с аспектом [CheckInvariant]. Вы можете представить себе преобразованное тело метода, имеющее следующую структуру:

NotDefaultOnEntry
try
{
  CheckInvariantOnEntry
  try
  {
    // original method body
    CheckInvariantOnSuccess
  }
  catch
  {
    CheckInvariantOnException
  }
  finally
  {
    CheckInvariantOnExit
  }
  NotDefaultOnSuccess
}
catch
{
  NotDefaultOnException
}
finally
{
  NotDefaultOnExit
}

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

Вы можете использовать зависимости роли аспекта, чтобы упорядочить эти аспекты. Примените [ProvideAspectRole] к NotDefaultAttribute и [AspectRoleDependency] к CheckInvariantAttribute, как показано ниже.

[Serializable]
[ProvideAspectRole(StandardRoles.Validation)]
public sealed class NotDefaultAttribute : LocationContractAttribute,
    ILocationValidationAspect<Guid>,
    ILocationValidationAspect<DateTime>,
    IValidableAnnotation
{
    // ...
}

[PSerializable]
[AspectRoleDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, StandardRoles.Validation)]
public sealed class CheckInvariantAttribute : OnMethodBoundaryAspect
{
    // ...
}

Другие вопросы по теме