根据现有属性更改代码?

时间:2011-04-19 10:26:18

标签: c# shared-libraries aop postsharp

我正在写一个在.net和silverlight之间共享的库。我有几个地方在做这个,以满足silverlight反序列化(无法访问私人成员):

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

我知道这个规则,如果setter是私有的并且定义了SILVERLIGHT,那么setter应该是内部的。

我可以使用像postsharp这样的面向方面的框架来帮助我减少这些代码,这样我就不需要指定任何内容了,它会检查属性,如果它具有DataMember属性并且setter是私有的,那么请设置内部而不是?

或者我可以使用其他技术吗?

编辑

似乎有些混乱。我的目标是完全避免使用编译器指令,但仍然拥有使用.net中的私有成员生成的代码以及可由DataContractDeserializer设置的成员Silverlight,无法访问私有成员。如果可能的话,我想自动修改silverlight构建中的属性,使其成为内部属性,同时除了源代码中的DataMember属性之外没有其他内容。

理想情况下,我认为解决方案类似于:

  • 写一个检查每个属性或字段的方面。
  • 如果属性/字段具有[DataMember]属性,那么
    • 如果存在silverlight编译器指令
      • 如果setter是私有的,则将其设置为内部(对于属性),或者如果将其声明为private,则将其设置为内部(对于字段)

但是我不确定使用post sharp这样的工具可以做到哪些。

2 个答案:

答案 0 :(得分:3)

其他答案要么攻击问题的优点,要么提出不直接回答问题的替代方法。问题是,在编译后,是否有办法在具有DataMember属性的属性中更改setter的可见性,以支持两个版本(.NET和Silverlight)。

我怀疑PostSharp SDK会支持这一点。但是,这是我在开发Afterthought时必须解决的问题,因为我需要更改由C#编译器生成的匿名静态委托的可见性(通常是私有的,直到我将它们设置为内部)。事后补充本身目前不直接支持您的场景,但它利用了开源Microsoft CCI库。 IL Mutator示例演示了如何使用CCI库加载已编译的程序集并通过创建可变副本来修改它。这个例子实际上比你的场景复杂得多,因为你不会修改IL,只是设置器的可见性。

这是在CCI中从mutator中更改方法可见性的示例:

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;

这是一个稍微简化的excerpt来自事后的支持者。在同一个类中还有一些示例,用于确定方法是否为setter(以set_,HideBySig等开头)。您只需要创建一个mutator,覆盖此示例中的方法,验证该方法是包含属性定义的DataMember属性的属性设置器,并更改可见性。

答案 1 :(得分:1)

简单的答案是否定的。 PostSharp是一个后编译框架,所以你不能使用你的编译器指令(正如你在你的问题中尝试做的那样)。您可以使用PostSharp

  1. 使用所需的访问器将属性引入类中(在设计时无法访问)在设计时可以将指令应用于方面以确定要注入的属性
  2. 或者使用反射来改变访问者(我认为你不能这样做)
  3. 另一种方法是使用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()
            {
    
            }
    
        }
    

    但实际上你需要重新考虑你的设计。