2015-06-03 2 views
1

Скажем, у меня есть класс менеджераКаков наилучший способ ограничить доступ к методу во время компиляции?

public class Manager { 
    public Item Create() { 
     ... 
     return new Item(...); 
    } 
} 

и у меня есть предмет класс:

public class Item { 
    [AllowCallBy(typeof(Manager))] 
    public Item(...) { 
    } 
    ... 
} 

Теперь я хотел бы использовать самый простой и самый простой способ анализировать такие атрибуты, как AllowCallBy в компилировать время и отображать ошибки или предупреждения. Если в этом конкретном случае класс, отличный от класса класса, пытается создать экземпляр Item с помощью new Item(...) Я хотел бы отобразить что-то вроде «не создавать экземпляр класса Item напрямую, вызывать диспетчер Manager.Create (...)».

Я полагаю, что хотя бы одна из систем: Roslyn, ReSharper, PostSharp или, может быть, что-то другое позволит мне сделать это или что-то очень близкое к тому, чего я пытаюсь достичь. Может ли кто-нибудь дать пример того, что использовать и как его использовать?

+6

Это звучит как код запах, я не знаю, как вы бы достичь чего-то подобного во время компиляции, но вы должны пересмотреть свой дизайн. Может быть создан статический метод или конструктор класса Item, который принимает параметр типа Manager, чтобы убедиться, что каждый элемент связан с менеджером или чем-то одним из этих строк ... – Habib

+0

Я считаю, что вы можете написать анализатор с Roslyn, который предупреждает вас, да. Если вы измените серьезность на Error, я полагаю, что это также помешало бы создать приложение. –

+1

Проблема заключается не в том, чтобы остановить другого разработчика, который не согласен с вашей предпосылкой, просто удалить это предупреждение. Я думаю, лучше было бы либо удалить определенные требования из класса 'Item', создав конструктор' Item' с параметром менеджера, либо добавив больше подробностей к вашему вопросу, который лучше описывает проблему *, которую вы пытаетесь решить * – Sayse

ответ

1

Хорошо, меня поразило. PostSharp lets you do exactly what you're looking for.В двух словах, вы бы использовать ComponentInternalAttribute для управления видимостью типа:

public class Item { 
    [ComponentInternal(typeof(Manager))] 
    public Item(...) { 
    } 
    ... 
} 

Согласно их документации, связанной выше, пытаясь вызвать конструктор Item «сек вне Manager даст предупреждение во время компиляции:

Метод Item.ctor не может ссылаться на [какой-либо другой метод] из-за ограничения [ComponentInternal].

Вы можете сделать это ошибка, изменяя уровень важности атрибута:

public class Item { 
    [ComponentInternal(typeof(Manager), Severity = SeverityType.Error)] 
    public Item(...) { 
    } 
    ... 
} 
0

Есть способ улучшить свои цели, чем ваш текущий подход, , учитывая, что вы действительно можете изменить этот код.

Вы можете, например, отметить конструктор класса Item как закрытый и добавить статический заводский метод к классу Item, который будет отвечать за создание экземпляра класса.

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

+0

Все это предполагает, что код может быть изменен. Это вполне может быть проблемой устаревшего дизайна, которая по уважительным причинам не может быть адаптирована. Именно там была бы удобна диагностика Roslyn: предотвратить повторение одной и той же проблемы, прежде чем команда найдет время для ее исправления. –

+0

В OP явно не упоминалось, что вы не можете изменить текущий код, поэтому я придумал этот ответ. Должен ли я его удалить? –

+0

Вот почему я специально подчеркнул, что «предупреждайте людей, работающих в одной и той же библиотеке». Вот почему их внутренняя работа не будет работать. Маркировка конструктора с private и создание статического метода не будет работать либо потому, что экземпляр менеджера имеет определенные поля, которые используются при инициализации элемента. Таким образом, элемент не может правильно создать себя. Только Менеджер может это сделать. –

3

Это, безусловно, code smell, поскольку @Habib упоминает (может ли кто-нибудь ссылку на конкретный?), Но без более полного примера трудно предложить альтернативы, кроме того, что уже было предложено в комментариях. Я бы посоветовал вам расширить свой выбор или переосмыслить свой дизайн.

Однако я могу представить один вариант, который я использовал в прошлом, хотя и не для этой цели. Можно отметить конструктор Item «S, как Obsolete:

public class Item { 
    [Obsolete("Don't instantiate Item class directly, call Manager.Create(...) instead")] 
    public Item(...) { 
    } 
    ... 
} 

Затем в Manager классе, вы определенно игнорировать это предупреждение, когда вы вызовете конструктор:

public class Manager { 
    public Item Create() { 
     ... 
#pragma warning disable 618 
     return new Item(...); 
#pragma warning restore 618 
    } 
} 

Таким образом, всякий раз, когда кто-то пытается создайте свои собственные Item в другом месте этого кода, они получат level 2 CS0618 warning, указав, что они не должны использовать метод (обратите внимание, что я не сказал не может) с точно текст, введенный в атрибут. Если включено warnings as errors (для всех предупреждений или только для этого), то это будет ошибка компиляции, как вы изначально хотели.

Знайте, ничего не мешает другим добавлять эти pragma заявления, чтобы обойти эту ошибку. Однако с помощью этого метода разработчик не может сказать, что они не знали, что они не должны использовать конструктор.

+0

Я думал об этом. Единственное, что мне не понравилось, это то, что ObsoleteAttribute используется так, как это не предполагается. Но в целом, возможно, это самое простое решение. Тем не менее, я надеюсь, что есть более чистая с одной из упомянутых систем. –

Смежные вопросы