C# 有没有更有效的方法来定义类似的公共属性
我有一个几乎有20个公共属性的类。这些属性的共同点是,它们都是字符串,并且由来自数据库不同表的数据填充 另外,集合是非常正常的,而get是特殊的,因为我需要调用一个特定的方法。目前对每个属性都执行此操作(见下文) 我的问题是:有没有另一种更有效的方法来做到这一点,也就是说,我不必以这种方式手工定义每个公共财产C# 有没有更有效的方法来定义类似的公共属性,c#,C#,我有一个几乎有20个公共属性的类。这些属性的共同点是,它们都是字符串,并且由来自数据库不同表的数据填充 另外,集合是非常正常的,而get是特殊的,因为我需要调用一个特定的方法。目前对每个属性都执行此操作(见下文) 我的问题是:有没有另一种更有效的方法来做到这一点,也就是说,我不必以这种方式手工定义每个公共财产 class myclass { private string _Firstname; private string _Lastname; .....
class myclass
{
private string _Firstname;
private string _Lastname;
.....
public string Firstname
{
get {
return ModifyStringMethod(this._Firstname);
}
set {
this._Firstname = value;
}
}
}
如上所述,每个公共财产看起来都一样。get调用ModifyStringMethod,将私有成员作为参数,而set只设置私有成员。您可以尝试使用自动生成代码。当您拥有简单、重复的代码模式,并且不希望某些情况与其他情况略有不同时,它们是完美的
只需定义一个包含属性名列表的XML,并让T4 template为每个属性生成分部类。另一种方法是使用类型和属性名作为变量创建一个简单的代码段。生成类的速度要快得多,而且您可以完全控制代码。当我过去遇到这种情况时,我在VS中使用了自定义代码片段来轻松创建属性。请参阅链接 然后,当必须添加新属性时,只需调用代码段并根据需要填写项目名称 虽然这不一定否定了拥有许多类似属性的必要性,
它确实使它们的创建变得更容易(与上面提到的使用T4模板相同)。但是,我个人并不喜欢这种解决方案,您可以这样做:
class MyClass
{
private IDictionary<string, string> propertyValueByName = new Dictionary<string, string>();
public string this[string propertyName]
{
get { return propertyValueByName[propertyName]; }
set { propertyValueByName[propertyName] = ModifyStringMethod(value); }
}
public string FirstName
{
get { return this["FirstName"]; }
set { this["FirstName"] = value; }
}
public string LastName
{
get { return this["LastName"]; }
set { this["LastName"] = value; }
}
}
public static class FormatStringExtensions {
public static string ModifyStringForOutput(this string me) {
if (me.Length > 10) {
return me.Substring(0, 10) + "...";
}
return me;
}
};
class-MyClass
{
私有IDictionary propertyValueByName=new Dictionary();
公共字符串此[string propertyName]
{
获取{return propertyValueByName[propertyName];}
设置{propertyValueByName[propertyName]=ModifyStringMethod(值);}
}
公共字符串名
{
获取{返回此[“FirstName”];}
设置{this[“FirstName”]=value;}
}
公共字符串姓氏
{
获取{返回此[“LastName”];}
设置{this[“LastName”]=value;}
}
}
另一个选项类似于Dion V.的解决方案,但它利用隐式转换使属性从外部表现为普通字符串,并使使用简单的自动属性成为可能。但是,只有当ModifyStringMethod
是静态的并且不需要来自类外部的参数时,这才有效
public struct EllipsisString
{
private string _value;
public string Value {get { return _value; }}
public EllipsisString(string value)
{
_value = value;
}
// implicit conversion from string so it is possible to just assign string to the property
public static implicit operator EllipsisString(string value)
{
return new EllipsisString(value);
}
public static implicit operator string(EllipsisString original)
{
return SpecialMethod(original.Value);
}
public override string ToString()
{
return SpecialMethod(Value);
}
private static string SpecialMethod(string value)
{
return value + "...";
}
}
而且用法很简单:
private EllipsisString FirstName { get; set; }
public void Method()
{
FirstName = "Thomas";
Console.WriteLine(FirstName);
Console.WriteLine(FirstName.Value);
}
使用反射的示例
class MyClass
{
public string FirstName { private get; set; }
public string LastName { private get; set; }
public string GetModifiedValue(string propertyName)
{
var prop = this.GetType().GetProperty(propertyName);
return ModifyStringMethod((string)prop.GetValue(this, null));
}
}
因此,要获得每个修改的值,而不是使用
MyClass.FirstName
,您可以使用MyClass.GetModifiedValue(“FirstName”)
,您可以创建自定义代码片段这里是我为自己创建的一个剪贴示例,用于自动创建带有更改通知的属性,您可以将其用作模板:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propnot</Title>
<Shortcut>propnot</Shortcut>
<Description>Code snippet for property and backing field with property change event</Description>
<Author>Radin Gospodinov</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>The variable backing this property</ToolTip>
<Default>myVar</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return this.$field$;}
set {
if(this.$field$ != value) {
$field$ = value;
this.RaisePropertyChanged(() => this.$property$);
}
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
普洛普诺
普洛普诺
带有属性更改事件的属性和备份字段的代码段
拉丁·戈斯波迪诺夫
膨胀
类型
属性类型
int
财产
属性名
我的财产
领域
支持此属性的变量
迈瓦尔
此.$property$);
}
}
}
$end$]>
是另一种选择
您只需在类上应用一个属性,并使用“get;set;”语法编写属性
PostSharp是一个.NET工具,它使开发人员能够将要执行的代码的各个方面应用于这些组件、名称空间、类或方法
具体地说,PostSharp使开发人员能够通过将属性应用于代码块来编写更少的代码,这些代码块稍后将在选择代码块的情况下插入并执行反映该方面的代码。这种方法大大减少了代码库中冗余的“管道”
常见用例包括以下内容:
- 伐木
- 保安
- 撤消/重做
- InotifyProperty已更改
- 例外处理
public class ModifyStringMethodInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
if (invocation.Method.Name.StartsWith("get_") &&
invocation.Method.ReturnType == typeof(string))
{
invocation.ReturnValue =
ModifyStringMethod((string)invocation.ReturnValue);
}
}
private static string ModifyStringMethod(string input)
{
return (input ?? "") + "MODIFIED";
}
}
上面的示例有一个Intercept方法,在调用属性时将调用该方法。您可以在示例invocation.procedure()中看到,这将继续对属性的调用
然后检查它是否为get_uu属性并返回字符串
if (invocation.Method.Name.StartsWith("get_") &&
invocation.Method.ReturnType == typeof(string))
然后修改方法的返回值
invocation.ReturnValue = ModifyStringMethod((string)invocation.ReturnValue);
3) 使用虚拟方法定义要添加此行为的对象(注意,我也可以在此处使用自动实现的属性)奖励
public class Intercepted
{
public virtual string A { get; set; }
}
4) 然后使用DynamicProxy中的ProxyGenerator类创建对象的实例
e、 g
这里的好处是您的对象是“干净”的,例如它们不需要了解ModifyStringMethodInterceptor,并且可以包含自动实现的属性,如果您有大量这些对象,它们将大量减少代码量
如果你需要进一步的控制,你可以通过广告来应用这种行为
Set ... MODIFIED
[AttributeUsage(AttributeTargets.Method)]
public class ModifyStringMethodAttribute : Attribute
{
}
public class Intercepted
{
public virtual string A { [ModifyStringMethod] get; set; }
}
if (invocation.Method.ReturnType == typeof(string) &&
invocation.Method.GetCustomAttributes(true)
.OfType<ModifyStringMethodAttribute>().Any())
{
invocation.ReturnValue =
ModifyStringMethod((string)invocation.ReturnValue);
}
public class MyExpando : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
//Want to create properties on initialization? Do it in the constructor
public MyExpando()
{
dictionary.Add("PreferredName", "Darth Sidious");
dictionary.Add("GreatDialog", "Something, something, darkside!");
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
bool success = dictionary.TryGetValue(binder.Name, out result);
if (success)
result = ModifiedValue(result);
return success;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
private string ModifiedValue(object val)
{
//Modify your string here.
if (val.ToString() != "Darth Sidious")
return "Something something complete";
return val.ToString();
}
}
dynamic x = new MyExpando();
x.FirstName = "Sheev";
x.LastName = "Palpatine"
Console.WriteLine(x.PreferredName + " says : \"" + x.GreatDialog + "\"");
Console.ReadKey();
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (!dictionary.ContainsKey(binder.Name))
return false;
dictionary[binder.Name] = value;
return true;
}
X.FirstName = "Some random long name";
Assert.AreEqual("Some random long name", X.FirstName);
public static class FormatStringExtensions {
public static string ModifyStringForOutput(this string me) {
if (me.Length > 10) {
return me.Substring(0, 10) + "...";
}
return me;
}
};
public class myclass {
public string FirstName { get; set; }
public string LastName {get; set; }
};
var instance = new myclass();
instance.FirstName = "01234567890123";
Console.WriteLine("Original Name {0}\nModified Name {1}\n",
instance.FirstName,
instance.FirstName.ModifyStringForOutput());