C# 使用属性简化属性
我有一个场景,我需要类中的属性映射到字典。下面是一个代码示例:C# 使用属性简化属性,c#,C#,我有一个场景,我需要类中的属性映射到字典。下面是一个代码示例: public string Foo { get { if (!PropertyBag.ContainsKey("Foo")) { return null; } return PropertyBag["Foo"]; } set { PropertyBag["Foo"] = value;
public string Foo
{
get
{
if (!PropertyBag.ContainsKey("Foo"))
{
return null;
}
return PropertyBag["Foo"];
}
set
{
PropertyBag["Foo"] = value;
}
}
我必须将此模式应用于多个属性。有没有一种方法可以使用属性来做到这一点
我知道PostSharp可以用于此目的,但我希望有一种不用它的方法来实现它。类测试
class Test
{
Dictionary<string,object> _values = new Dictionary<string, object>();
public string Foo
{
get
{
var value = GetValue();
return value == null ? string.Empty : (string)value;
}
set
{
SetValue(value);
}
}
private object GetValue()
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
if (_values.ContainsKey(key)) return _values[key];
return null;
}
private void SetValue(object value)
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
_values[key] = value;
}
private string GetGenericName(string key)
{
return key.Split('_')[1];
}
}
{
字典_值=新字典();
公共字符串Foo
{
得到
{
var value=GetValue();
返回值==null?字符串。空:(字符串)值;
}
设置
{
设置值(值);
}
}
私有对象GetValue()
{
var stack=new StackTrace();
var key=GetGenericName(stack.GetFrame(1.GetMethod().Name);
if(_values.ContainsKey(key))返回_值[key];
返回null;
}
私有void SetValue(对象值)
{
var stack=new StackTrace();
var key=GetGenericName(stack.GetFrame(1.GetMethod().Name);
_值[键]=值;
}
私有字符串GetGenericName(字符串键)
{
返回键。拆分(“”“)[1];
}
}
您可以编写一个GetValueOrDefault
扩展方法并稍微减少代码
public static class DictionaryExtensions
{
public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey,TValue> self, TKey key)
{
TValue value;
self.TryGetValue(key,out value);
return value;
}
}
public string Foo
{
get
{
return PropertyBag.GetValueOrDefault("Foo");
}
set
{
PropertyBag["Foo"] = value;
}
}
公共静态类字典扩展
{
公共静态TValue GetValuerDefault(此IDictionary self,TKey)
{
t价值;
self.TryGetValue(键,输出值);
返回值;
}
}
公共字符串Foo
{
得到
{
返回属性bag.GetValueOrDefault(“Foo”);
}
设置
{
PropertyBag[“Foo”]=价值;
}
}
.我觉得这就像是一种代码气味。最好使用常规POCO,并仅在需要时将其转换为字典
public class BlogPost
{
public string Title { get; set; }
public string Body { get; set; }
public int AuthorId { get; set; }
public Dictionary<string, object> ToDictionary()
{
return this.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(this, null));
}
}
信用:在GitHub
这应该为每个对象添加一个ToDictionary
方法
编辑:来自以下评论
为了提供一点上下文,我使用实体框架,并且我希望在一个表中保留一个类层次结构,同时避免到处出现空列
实体框架支持多表继承。在您的情况下,这可能是一个更好的解决方案。如果您至少使用.NET 4.5,那么您就有了名为
的MemberNameAttribute
,您可以这样使用它:
class SomeClass
{
public string Foo
{
get
{
return GetPropertyValue();
}
set
{
SetPropertyValue( value );
}
}
private string GetPropertyValue( [CallerMemberName] string name = null )
{
string value;
PropertyBag.TryGetValue( name, out value );
return value;
}
private void SetPropertyValue( string value, [CallerMemberName] string name = null )
{
PropertyBag[name] = value;
}
}
这将导致编译器为您填写成员的名称。如果您不使用(或不能使用).NET 4.5,另一种选择是按照另一个答案中的建议利用它。我想这不会起到替代作用,对吧?属性在这里没有帮助。
PropertyBag
的类型是什么?我相信您可以将getter简化为单个方法调用。字典下面的答案可能与我所能告诉您的代码一样简洁。@user472875答案是一个黑客,不要在您的产品代码中使用它。是的,这肯定有助于消除任何地方的神奇字符串。在这种情况下,这可能是最好的选择。不要这样做-在与调试无关的代码中使用StackTrace
是错误的()。我同意这是一个脆弱的解决方案,但符合要求。唯一的另一种选择是海报已经提供的内容。为了提供一点上下文,我使用实体框架,我希望在一个表中保留一个类层次结构,同时避免到处都是空列。所有这些属性在代码中都标记为[NotMapping],并且只有字典被序列化。这就是说,这个解决方案是完美的。反序列化时我需要执行反向操作,但它消除了所有额外的代码。这是我使用的初始解决方案。在我的场景中,我发现它难以管理。这些对象表示我需要能够同时监视的任务。多表继承方法创建了n个我必须连接的表,再加上一个额外的鉴别器列,我必须自己添加该列以确定我正在查看的任务类型。此外,任务类的集合正在迅速增加。你觉得怎么样?我看的一个例子是,开发人员很快就想编写一个新任务。在这种情况下,随着编码的进行,任务中的属性可能会经常更改,这意味着每次此类更改都需要一个DB迁移脚本。实际上,听起来您需要一个任务POCO和表,然后在任务和任务类型之间创建一个联接表。继承在这里是一种反模式。您有一个通用任务,可以标记为一个或多个类型。
class SomeClass
{
public string Foo
{
get
{
return GetPropertyValue();
}
set
{
SetPropertyValue( value );
}
}
private string GetPropertyValue( [CallerMemberName] string name = null )
{
string value;
PropertyBag.TryGetValue( name, out value );
return value;
}
private void SetPropertyValue( string value, [CallerMemberName] string name = null )
{
PropertyBag[name] = value;
}
}