Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用属性简化属性_C# - Fatal编程技术网

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;
    }
}