使用MongoDB C#驱动程序的BsonElement属性和自定义反序列化逻辑

时间:2015-07-14 12:03:57

标签: c# mongodb mongodb-.net-driver

考虑以下示例:

    public class Foo
    {
        private string _text;

        [BsonElement("text"), BsonRequired]
        public string Text
        {
            get { return _text; }
            set
            {
                _text = value;
                Bar(_text);
            }
        }

        private void Bar(string text)
        {
            //Only relevant when Text is set by the user of the class,
            //not during deserialization
        }
    }

当类的用户为属性分配新值并且在MongoDB C#驱动程序的对象反序列化期间,调用Text属性的setter以及随后的方法Bar。我需要的是确保仅在用户设置Bar属性时调用Text,而不是在反序列化期间调用。{/ p>

我认为两种解决方案并不适合我:

第一种是将BsonElement属性移动到支持字段。但是,据我所知,BsonElement属性在MongoDB C#驱动程序的查询构建中使用,因此我将无法在查询中使用Text属性。

第二个解决方案是将Text setter设为私有,并添加一个方法,通过该方法,类的用户将设置Text属性,并且Bar方法将在其中调用。但是,Text setter在现有解决方案中经常使用,我有点不愿意在所有文件中更改70多个调用。此外,代码的可读性会降低。

在保留属性的BsonElement属性的同时,是否有更简洁的方法来分离反序列化和用户提示的属性更改?

3 个答案:

答案 0 :(得分:1)

为什么不为用户创建单独的属性,为同一个私有变量创建DB,如下所示

public class Foo
{
    private string _text;

    [BsonElement("text"), BsonRequired]
    public string TextDB
    {
        get { return _text; }
        set
        {
            _text = value;
        }
    }

    [BsonIgnore]
    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            Bar(_text);
        }
    }

    private void Bar(string text)
    {
        //Only relevant when Text is set by the user of the class,
        //not during deserialization
    }
}

答案 1 :(得分:0)

你可以使用一个小技巧实现一种属性监听器。

用法是:

// Working with some foo here...
var foo = new Foo();
foo.Text = "Won't fire anything";

using (var propertyListener = new FooPropertiesListener(foo))
{
    foo.Text = "Something will fire you listener";
}

// Some more work with foo here...
foo.Text = "Won't fire anything";

它背后的实现,如:

<强> FooPropertiesListener

public class FooPropertiesListener : IDisposable
{
    private readonly Foo Foo;

    public FooPropertiesListener(Foo foo)
    {
        this.Foo = foo;
        this.Foo.PropertiesListener = this;
    }

    public void Bar(string text)
    {
        //Only relevant when Text is set by the user of the class,
        //not during deserialization
    }

    public void Dispose()
    {
        Foo.PropertiesListener = null;
    }
}

<强>富

public class Foo
{
    internal FooPropertiesListener PropertiesListener;

    private string _text;

    [BsonElement("text"), BsonRequired]
    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            if (PropertiesListener != null)
            {
                PropertiesListener.Bar(_text);
            }
        }
    }
}

答案 2 :(得分:0)

我知道这个问题已经过时了,但我仍然希望像其他人那样帮助其他人绊倒这个问题。

它基本上归结为一些非常简单的事情:序列化和反序列化不仅限于公共字段和属性!

下一个例子将涵盖原始问题,而不必发明可疑的二级属性:

public class Foo
{
    [BsonElement("Text"), BsonRequired]
    private string _text;

    [BsonIgnore]
    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            Bar(_text);
        }
    }

    private void Bar(string text)
    {
        //Only relevant when Text is set by the user of the class,
        //not during deserialization
    }
}

只需将您的BsonElement课程放在支持字段上,然后告诉BsonIgnore该属性。 你可以在getter和setter中做任何你喜欢的事情,而不必担心现在在私有字段级别发生的反序列化。

希望这有助于某人!