C# 有没有一种方法可以在C中通过代码重用实现多个属性?
我有一门课是这样的:C# 有没有一种方法可以在C中通过代码重用实现多个属性?,c#,properties,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 _getV
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
}
...
}
var x = Abc.NewInstance();
x.City = "hi";
var y = x.State;
是的,我知道跟踪/反射很慢;别炒我,兄弟
考虑到所有属性的声明都是相同的,我希望能够用一些简单/干净的方法来声明它们,而不需要反复重复相同的get/set代码。
我需要所有属性的智能感知,这就排除了使用例如ExpandooObject
如果我在C/C++领域,我可以使用宏,例如:
#define DEFPROP(name) \
public string name \
{ \
get { return _getValue(); } \
set { _setValue(value); } \
} \
然后:
但这当然是C
所以。。。有什么好主意吗
编辑
我猜我原来的帖子不够清楚。
My helper函数_getValue根据调用的属性进行一些定制的查找和处理。它不仅仅存储/检索一个简单的特定于道具的值。
如果我只需要简单的值,那么我只需要使用自动属性
public string { get; set; }
就这样,就不会问这个问题了。有人想出了如何在c中使用c预处理器 看
但是:您应该避免使用堆栈跟踪!!!!将字符串传递给_getValuename或自动生成字段。如果您使用堆栈跟踪,您必须停用方法内联以及尾部调用优化,但不确定这是否可行。这里有一个使用RealProxy和MarshallByRefObject的恶意攻击,它将让您拦截属性调用并执行任何您想要的操作
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);
}
}
}
那么当你这样使用它的时候:
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
}
...
}
var x = Abc.NewInstance();
x.City = "hi";
var y = x.State;
您将在控制台窗口中看到以下内容:
Before set_City
After set_City
Before get_State
After get_State
首先:注入调用成员名称,因此不需要反射:
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模板确实比宏有优势,代码可以随时重新生成。因此,即使在初始生成之后,也可以应用对源代码的自适应(可能是实现自适应或属性重命名)。我制作了一个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安装中。打开代码段管理器工具/代码段管理器。
单击导入按钮。
转到保存代码段的位置,选择它,然后单击“打开”。
此时将打开“导入代码段”对话框,要求您从右侧窗格中的选项中选择在何处添加代码段。选择之一应该是我的代码片段。选择它并单击Finish,然后单击OK。
将代码段复制到以下位置:
%USERPROFILE%\Documents\Visual Studio 2013\Code Snippets\Visual C\My Code Snippets
在文件中,单击关联菜单上的“插入代码段”,然后单击“我的代码段”。您应该会看到一个名为My Visual Basic代码段的代码段。双击它。
笔记:
在键入当前myprop块中的任何内容后,只需点击Tab,就可以让VisualStudio文本编辑器为您插入这些内容 T4?Visual Studio宏。。。这么多的可能性……另一件事要考虑的是,如果你不需要做任何额外的处理。您只需执行公共字符串City{get;set;}即可。为什么公共字符串City{get;set;}从未为我编译过。请阅读C中的自动属性。这就是您所关注的。请说明您在getValue和setValue中执行的查找/处理类型。可能有一个解决方案,但告诉您我们需要了解更多关于您正在做什么的解决方案可能是您想要的,但我们需要了解更多才能确定,您可能也需要T4。如果你告诉我们你想做什么,我们可以告诉你你需要什么。请记住,当受影响的文件处于源代码控制之下并且您使用的是自动构建过程时,这可能是一个问题。TFS通常将文件标记为只读,并将其用作未签出文件的引用。该预处理器帖子确实引起了很多强烈的意见:我这样看:如果使用预处理器阻止使用堆栈跟踪来确定属性名称,这是一个改进。在C 5编译器中,添加了CallerMemberNameAttribute:从不知道创建透明代理的可能性。。。美好的但是我更喜欢AOP而不是反射…@ChaosPandion啊,谢谢你在参数中添加类型-我显然错过了这一点。。。