Изменить код на основе существующего атрибута? - PullRequest
2 голосов
/ 19 апреля 2011

Я пишу библиотеку, которая используется совместно .net и silverlight.У меня есть несколько мест, где я делаю это, чтобы выполнить десериализацию Silverlight (которая не может получить доступ к закрытым членам):

    [DataMember (IsRequired = true)]
    public Object MyProperty { get; 
#if SILVERLIGHT
        internal    
#else
        private 
#endif
         set; }

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

Могу ли я использовать аспектно-ориентированную среду, такую ​​как postsharp, чтобы помочь мне уменьшить этот код, чтобы мне не нужно ничего указывать, и он будет проверять свойство, еслиимеет атрибут DataMember, и установщик является личным, затем вместо этого установите установщик внутренним?

Или есть какой-то другой метод, который я мог бы использовать для этого?*

Кажется, есть некоторая путаница.Моя цель - избегать директив компилятора вообще , но по-прежнему иметь код, который генерируется с закрытым членом в .net и с элементом, который может быть установлен с помощью DataContractDeserializer в Silverlight, которыйне может получить доступ к частным пользователям.Если возможно, я бы хотел автоматически изменить свойство в сборке silverlight, чтобы оно было внутренним, при этом в источнике не было ничего, кроме атрибута DataMember.

В идеале я вижу решение, похожее на:

  • Напишите аспект, который проверяет каждое свойство или поле.
  • Если свойство / поле имеет атрибут [DataMember], тогда
    • Если существует директива компилятора silverlight, тогда
      • , если установщик является личным, сделать его внутренним (для свойств) или если он объявлен как частный, сделать его внутренним (для полей)

но я не уверен, какие биты этого можно было бы сделать с помощью такого инструмента, как Post Sharp.

Ответы [ 2 ]

3 голосов
/ 07 мая 2011

Другие ответы либо атакуют суть проблемы, либо представляют альтернативные подходы, которые не дают прямого ответа на вопрос. Вопрос заключался в том, существует ли способ изменить видимость метода установки для свойства с атрибутом DataMember после его компиляции для поддержки двух версий (.NET и Silverlight).

Я подозреваю, что PostSharp SDK поддержит это. Однако эту проблему мне пришлось решить при разработке Afterthought , поскольку мне нужно было изменить видимость анонимных статических делегатов, генерируемых компилятором C # (обычно закрытых, пока я не сделал их внутренними). Сама вторичная мысль в настоящее время не поддерживает ваш сценарий напрямую, но использует библиотеки с открытым исходным кодом Microsoft CCI , которые поддерживают. Пример IL Mutator показывает, как использовать библиотеки CCI для загрузки скомпилированной сборки и изменения ее путем создания изменяемой копии. Пример на самом деле намного сложнее, чем ваш сценарий, так как вы не будете изменять IL, только видимость сеттера.

Это пример изменения видимости метода из мутатора в CCI:

public override MethodDefinition Mutate(MethodDefinition methodDef)     
{
    // Automatically make all private static methods to have internal scope
    if (methodDef.IsStatic && methodDef.Visibility == TypeMemberVisibility.Private)
        methodDef.Visibility = TypeMemberVisibility.Assembly;

Это слегка упрощенный отрывок из дополнения Afterthought. В том же классе также есть примеры того, как определить, является ли метод установщиком (начинается с set_, HideBySig и т. Д.). Вам просто нужно создать мутатор, переопределить метод в этом примере, убедиться, что метод является установщиком свойства с атрибутом DataMember в определении содержащего свойства, и изменить видимость.

1 голос
/ 19 апреля 2011

Простой ответ - НЕТ. PostSharp - это среда посткомпиляции, поэтому вы не можете использовать директивы компилятора (как вы пытаетесь это сделать в своем вопросе). Вы можете использовать PostSharp для

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

Альтернативой является использование шаблонов T4 для генерации этих классов для вас

Редактировать: Пример внедрения свойства

[Serializable]
    [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
    public class PropInj : InstanceLevelAspect
    {
#if SILVERLIGHT
        [IntroduceMember(OverrideAction = MemberOverrideAction.Ignore, IsVirtual=true, Visibility=Visibility.FamilyAndAssembly)]
        public string MyProperty { get; set; }
#else
        [IntroduceMember(OverrideAction = MemberOverrideAction.Ignore, IsVirtual = true, Visibility = Visibility.Private)]
        public string MyProperty { get; set; }
#endif
    }

    [PropInj]
    public class test
    {
        //public int MyProperty { get; set; }

        public test()
        {

        }

    }

но на самом деле вам нужно переосмыслить свой дизайн.

...