This project is read-only.
2

Closed

IValueProvider.Value is incorrect unless IValueProvider is being observed !?

description

Hi Thomas
 
I've just started using Obtics and on the whole it's excellent. Well done!
 
I understand there are a few undocumented gotchas (eg. http://obtics.codeplex.com/Thread/View.aspx?ThreadId=68881), but I believe I've found a nasty bug whereby the IValueProvider<>.Value is incorrect when;
a. Expression contains System.Linq.Enumerable.Intersect() that returns non-zero AND
b. IValueProvider isn't bound/observed.
 
The following code illustrates the problem;
a. Class A - expression without Intersect that works without requiring the obtics property to be observed.
b. Class B - expression with Intersect that fails unless the obitcs property is observed.
 
I'm assuming the problem isn't unique to Intersect(), but instead possibly related to;
  • inter-dependencies in the constructed expression tree?
  • delayed execution not firing when the IValueProvider<>.Value is read? I suspect this is the issue.
     
    I'd really appreciate a fix to this issue as these expressions are typical (albeit it more complex) of those I need to observe.
     
    Many Thanks
     
     
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using Obtics.Values;
     
    namespace ObticsValueTest
    {
    // simpler expression that doesn't involve Intersect()
    public class A
    {
    public ObservableCollection<object> OC1 = new ObservableCollection<object>();
    public ObservableCollection<object> OC2 = new ObservableCollection<object>();
     
    public int Method()
    {
        return OC1.Count() + OC2.Count();
    }
    public IValueProvider<int> Property
    {
        get { return ExpressionObserver.Execute(() => OC1.Count() + OC2.Count()); }
    }
    }
     
    // more cmplex expression using Intersect()
    public class B
    {
    public ObservableCollection<object> OC1 = new ObservableCollection<object>();
    public ObservableCollection<object> OC2 = new ObservableCollection<object>();
     
    public int Method()
    {
        return OC1.Intersect(OC2).Count();
    }
    public IValueProvider<int> Property
    {
        get { return ExpressionObserver.Execute(() => OC1.Intersect(OC2).Count()); }
    }
    }
     
     
    class Program
    {
    static void Main()
    {
        // works
        var a1 = new A();
        Test(a1);
     
        // works
        var b1 = new B();
        ((INotifyPropertyChanged) b1.Property).PropertyChanged += (s, e) => { };
        Test(b1);
    
        // fails
        var b2 = new B();
        Test(b2);
    }
     
    static void Test(A a)
    {
        var o1 = new object();
        var o2 = new object();
     
        a.OC1.Add(o1);
        if (a.Method() != a.Property.Value)
            throw new Exception();
     
        a.OC2.Add(o1);
        if (a.Method() != a.Property.Value)
            throw new Exception();
     
        a.OC2.Add(o2);
        if (a.Method() != a.Property.Value)
            throw new Exception();
    }
     
    static void Test(B b)
    {
        var o1 = new object();
        var o2 = new object();
     
        b.OC1.Add(o1);
        if (b.Method() != b.Property.Value)
            throw new Exception();
     
        b.OC2.Add(o1);
        if (b.Method() != b.Property.Value)
            throw new Exception();
     
        b.OC2.Add(o2);
        if (b.Method() != b.Property.Value)
            throw new Exception();
    }
    }
    }

file attachments

Closed Jun 26, 2011 at 8:34 AM by Throb

comments

wrote Jan 5, 2010 at 8:18 PM

Associated with changeset 33114.

Throb wrote Jan 5, 2010 at 8:25 PM

Some component used a cache when it shouldn't.. fixed.

Thanks for reporting the issue.

Btw. Though this was a bug. I doubt wether it is a good idea to use obtics when you are not using the live aspect of it? i.e. directly or indirectly are registering for change events.

Regs,

Thomas.

wrote Jan 5, 2010 at 8:25 PM

tstojano wrote Jan 6, 2010 at 12:17 AM

Many thanks for fixing the bug. I'll try it today.

Agreed, the typical obtics scenario would be to have another entity register for change events (eg. WPF view binding to obtics backed model). In addition to this, we have some exceptional scenarios;
a. Unit tests that validate the obtics backed model without the presence of (a binding) view.
b. Obtics expressions that perform some fairly complex (and slow) calculations that we only want to execute once when an observable parameter changes, but whose result is not explicitly bound.

Thanks once again for the fix.

Regards
Tibor

wrote Jun 26, 2011 at 8:34 AM

wrote Feb 14, 2013 at 2:41 AM

wrote May 16, 2013 at 5:55 AM