使用属性来简化属性
本文关键字:属性 | 更新日期: 2023-09-27 18:16:44
我有一个场景,我需要类中的属性映射到字典。下面是一个代码示例:
public string Foo
{
get
{
if (!PropertyBag.ContainsKey("Foo"))
{
return null;
}
return PropertyBag["Foo"];
}
set
{
PropertyBag["Foo"] = value;
}
}
我必须将此模式应用于多个属性。有没有办法使用属性来做到这一点?
我知道PostSharp会为这个目的工作,但我希望有一种方法可以做到这一点,而不使用它
对我来说这感觉像是代码的味道。最好使用常规poco,并仅在需要时将其转换为Dictionary。
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));
}
}
启示:如何将class转换为Dictionary?
老实说,你的POCO上的ToDictionary
方法看起来像一个代码气味。最好重构你的代码,让poco到字典的转换在它自己的层中进行,可能是作为一个服务。
编辑:这个要点是我在谷歌搜索"c#转换对象到字典"时发现的,可以提供一个更通用的解决方案,可能比我拼凑的例子更防弹:
要点:https://gist.github.com/jarrettmeyer/798667
摘自要点:
public static class ObjectToDictionaryHelper
{
public static IDictionary<string, object> ToDictionary(this object source)
{
return source.ToDictionary<object>();
}
public static IDictionary<string, T> ToDictionary<T>(this object source)
{
if (source == null)
ThrowExceptionWhenSourceArgumentIsNull();
var dictionary = new Dictionary<string, T>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
AddPropertyToDictionary<T>(property, source, dictionary);
return dictionary;
}
private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
{
object value = property.GetValue(source);
if (IsOfType<T>(value))
dictionary.add(property.Name, (T)value);
}
private static bool IsOfType<T>(object value)
{
return value is T;
}
private static void ThrowExceptionWhenSourceArgumentIsNull()
{
throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
}
}
来源:jerrettmeyer at GitHub
这应该为每个对象添加一个ToDictionary
方法。
编辑:来自以下注释
给一点上下文,我正在使用实体框架,我有一个类层次结构,我想保持在一个表中,同时避免空列无处不在。
实体框架支持多表继承。
您可以编写一个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;
}
}
您可以使用表达式消除魔术字符串。
如果你至少使用。net 4.5,那么你有CallerMemberNameAttribute
,你可以这样使用:
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,另一种选择是利用另一个答案中建议的表达式树。
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];
}
}