有没有办法在C#中使用代码重用来实现多个属性?

时间:2015-06-11 19:23:27

标签: c# properties

我有一个类似这样的课程:

public class Abc
{
   public string City
   {
      get { return _getValue(); }
      set { _setValue(value); }
   }
   public string State
   {
      get { return _getValue(); }
      set { _setValue(value); }
   }
   private string _getValue()
   {
      // determine return value via StackTrace and reflection
   }
   ...
}

(是的,我知道StackTrace /反射很慢;不要让我感到震惊)

鉴于 ALL 属性被声明为相同,我能够做的就是有一些简单/干净的方式来声明它们而不需要复制相同的get / set代码一遍又一遍。
我需要所有属性的Intellisense,这排除了使用例如。 ExpandoObject

如果我在C / C ++领域,我可以使用宏,例如:

#define DEFPROP(name) \
   public string name \
   { \
      get { return _getValue(); } \
      set { _setValue(value); } \
   } \

然后:

public class Abc
{
   DEFPROP(City)
   DEFPROP(State)
   ...
}

但当然这是C#。

那么......任何聪明的想法?

####编辑###
我想我原来的帖子不够清楚 我的帮助函数_getValue()做了一些自定义的查找&基于正在调用Property的处理。它不仅仅存储/检索一个简单的道具特定值 如果我需要的只是简单值,那么我只使用自动属性

public string { get; set; }

并完成它,并且不会问这个问题。

4 个答案:

答案 0 :(得分:5)

首先关闭:CallerMemberNameAttribute会注入主叫成员名称,因此无需反思:

public class Abc
{
   public string City
   {
      get { return _getValue(); }
      set { _setValue(value); }
   }
   public string State
   {
      get { return _getValue(); }
      set { _setValue(value); }
   }
   private string _getValue([CallerMemberName] string memberName = "")
   {
   }

   private void _setValue(string value,
                          [CallerMemberName] string memberName = "")
   {
   }
}

其次:通过利用T4模板生成.cs文件,可以实现类型成员的生成:

<#@ output extension=".cs" #>
<#
var properties = new[]
{
    "City",
    "State"
};
#>
using System.Runtime.CompilerServices;

namespace MyNamespace
{
    public class Abc
    {
<# foreach (var property in properties) { #>
        public string <#= property #>
        {
            get { return _getValue(); }
            set { _setValue(value); }
        }
<# } #>
        private string _getValue([CallerMemberName] string memberName = "") {}
        private void _setValue(string value, [CallerMemberName] string memberName = "") {}
    }
}

您甚至可以将_setValue_getValue卸载到包含文件中,以便为其他模板提供可重用性。

T4模板确实具有优于宏的优势,可以随时重新生成代码。因此,即使在初始生成之后,也可以应用对源代码的调整(可能是实现自适应或属性重命名)。

答案 1 :(得分:1)

这是一个讨厌的hack,使用RealProxy和MarshalByRefObject,它可以让你拦截属性调用并做你想做的任何事情。

public class Abc : MarshalByRefObject
{
    public string City { get; set; }
    public string State { get; set; }

    private Abc()
    {
    }

    public static Abc NewInstance()
    {
        var proxy = new AbcProxy(new Abc());
        return (Abc)proxy.GetTransparentProxy();
    }
}

public class AbcProxy : RealProxy
{
    private readonly Abc _realInstace;

    public AbcProxy(Abc instance) : base(typeof (Abc))
    {
        _realInstace = instance;
    }

    public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
    {
        var methodCall = msg as IMethodCallMessage;
        var methodInfo = methodCall.MethodBase as MethodInfo;
        Console.WriteLine("Before " + methodInfo.Name);
        try
        {
            var result = methodInfo.Invoke(_realInstace, methodCall.InArgs);
            Console.WriteLine("After " + methodInfo.Name);
            return new ReturnMessage(result, null, 0,
             methodCall.LogicalCallContext, methodCall);
        }
        catch (Exception e)
        {
            return new ReturnMessage(e, methodCall);
        }
    }
}

然后当你像这样使用它时:

var x = Abc.NewInstance();

x.City = "hi";
var y = x.State;

您将在控制台窗口中看到以下内容:

Before set_City
After set_City
Before get_State
After get_State

答案 2 :(得分:0)

有人想出如何在c#

中使用c预处理器

请参阅https://stackoverflow.com/a/15703757/417577

但是:您应该避免使用堆栈跟踪为您的目的!将字符串传递给_getValue(“name”)或自动生成字段。如果使用堆栈跟踪,则必须停用方法内联(简单)以及尾调用优化(不确定是否可行)。

答案 3 :(得分:0)

我制作了一个Visual Studio代码段,为您自动生成代码

这是.snippet文件内容:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>MyProp</Title>
            <Author>ryanyuyu</Author>
            <Description>Auto get/set property</Description>
            <Shortcut>myprop</Shortcut>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>propName</ID>
                    <Default>MyProperty</Default>
                    <ToolTip>The name of the property.</ToolTip>
                </Literal>
            </Declarations>
            <Code Language="CSharp">
                <![CDATA[
        public string $propName$
        {
            get { return _getValue(); }
            set { _setValue(value); }
        }
            ]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

将此XML文档另存为.snippet文件。然后,只需按照MSDN To Add a Code Snippet to Visual Studio

中的这些步骤操作即可
  1. 您可以使用代码片段管理器将自己的代码段添加到Visual Studio安装中。打开代码片段管理器(工具/代码片段管理器)。
  2. 单击“导入”按钮。
  3. 转到保存代码段的位置,选择它,然后单击“打开”。
  4. 将打开“导入代码段”对话框,要求您从右侧窗格的选项中选择添加片段的位置。其中一个选择应该是My Code Snippets。选择它,然后单击“完成”,然后单击“确定”。
  5. 将代码段复制到以下位置: %USERPROFILE%\ Documents \ Visual Studio 2013 \ Code Snippets \ Visual C#\ My Code Snippets
  6. 在文件中,单击上下文菜单上的“插入片段”,然后单击“我的代码片段”。您应该看到名为My Visual Basic Code Snippet的代码段。双击它。
  7. 注意:

    输入<ShortCut>块中的任何内容(当前为myprop)后,只需按 Tab 即可让Visual Studio文本编辑器为您插入。