繁体   English   中英

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

[英]Is there a way to implement multiple Properties with code reuse in C#?

我有一个类是这样的类:

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 /反射很慢;不要惹我生气)

鉴于所有属性都被声明为相同,我能够做的就是有一些简单/干净的方式来声明它们,而不需要反复复制相同的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执行一些自定义查找和处理。 它不仅存储/检索简单的特定于prop的值。
如果我需要的只是简单的值,那么我只使用自动属性

public string { get; set; }

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

首先: 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 = "")
   {
   }
}

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

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

这是一个讨厌的黑客使用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

有人想出如何在c#中使用c预处理器

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

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

我制作了一个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 添加代码片段到Visual Studio

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

笔记:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM