├── .gitignore ├── ContinuousLinq ├── .gitignore ├── Expressions │ ├── Curry1.cs │ ├── ParameterNode.cs │ ├── SubscriptionTree.cs │ ├── ConstantNode.cs │ ├── Curry.tt │ ├── PropertyAccessTreeNode.cs │ ├── CompiledExpressionCache.cs │ ├── PropertyAccessNode.cs │ ├── ClosureToStaticExpressionFactory.cs │ └── SubscriptionNode.cs ├── ContinuousLinq.csproj.vspscc ├── Collections │ ├── OrderedReadOnlyContinuousCollection.cs │ ├── ReadOnlyAdapterContinuousCollection.cs │ ├── ReadOnlyTwoCollectionOperationContinuousCollection.cs │ ├── PassThroughReadOnlyContinuousCollection.cs │ ├── ContinuousLinqHelperException.cs │ ├── GroupedReadOnlyContinuousCollection.cs │ ├── ThenByReadOnlyContinuousCollection.cs │ └── ConcatReadOnlyContinuousCollection.cs ├── DictionaryExtensions.cs ├── Reactive │ ├── DependsOnMethod.cs │ ├── BridgeMethod.cs │ ├── DependsOn.cs │ └── ReactiveObject.cs ├── Aggregation │ ├── PausedAggregation.cs │ └── StdDev.cs ├── Properties │ └── AssemblyInfo.cs ├── EventExtensions.tt ├── ReferenceCountTracker.cs ├── WeakEvents │ ├── WeakPropertyChangedEventManager.cs │ └── WeakPropertyChangedCallback.cs └── PropertyNotifier.cs ├── ContinuousLinqSL ├── .gitignore ├── ContinuousLinqSL.csproj.vspscc └── Properties │ └── AssemblyInfo.cs ├── OrderBookDemo ├── .gitignore ├── Resources │ └── logo.png ├── Models │ ├── Order.cs │ ├── OrderCollection.cs │ ├── Vwap.cs │ └── StockTransaction.cs ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ └── Resources.Designer.cs ├── OrderBookDemo.csproj.vspscc ├── App.xaml.cs ├── App.xaml ├── Views │ └── MainWindow.xaml.cs └── Converters │ ├── PriceConverter.cs │ └── TickCollectionFormatter.cs ├── SilverlightTest ├── .gitignore ├── Properties │ ├── AppManifest.xml │ └── AssemblyInfo.cs ├── App.xaml ├── SilverlightTest.csproj.vspscc ├── MainPage.xaml ├── MainPage.xaml.cs ├── Model.cs └── App.xaml.cs ├── PerformanceConsole ├── .gitignore ├── PerformanceConsole.csproj.vspscc ├── Properties │ └── AssemblyInfo.cs ├── Program.cs └── PerformanceConsole.csproj ├── ContinuousLinq.UnitTests ├── .gitignore ├── ContinuousLinq.UnitTests.csproj.vspscc ├── PropertyAccessNodeTest.cs ├── WeakEvents │ ├── ListenerStub.cs │ ├── WeakEventHandlerTest.cs │ ├── WeakPropertyBridgeTest.cs │ └── WeakPropertyChangedEventManagerTest.cs ├── Extensions.cs ├── DistinctTest.cs ├── AsReadOnlyTest.cs ├── ContinuousContainsTest.cs ├── ContinuousCountTest.cs ├── Properties │ └── AssemblyInfo.cs ├── PassThroughReadOnlyContinuousCollectionTest.cs ├── ReferenceCountTrackerTest.cs ├── DynamicPropertyTest.cs ├── ThenByTest.cs ├── ClosureToStaticExpressionFactoryTest.cs ├── SubscriptionTreeTest.cs ├── PausedAggregationTest.cs ├── ClinqTestFactory.cs ├── FirstOrDefaultTest.cs ├── SkipListTest.cs ├── ContinuousSumTest.cs ├── GroupByTest.cs ├── ContinuousMaxTest.cs ├── SelectTest.cs ├── TestUtilities.cs ├── NotifyingPerson.cs ├── WhereTest.cs ├── SelectReadOnlyContinuousCollectionDuplicatesTest.cs ├── SubscriptionNodeTest.cs └── ClosureToStaticExpressionTransformerTest.cs ├── ContinuousLinqSL.UnitTests ├── .gitignore ├── Libs │ ├── nunit.framework.dll │ ├── nunit.silverlight.dll │ └── Rhino.Mocks 3.5.Silverlight.dll ├── ContinuousLinqSL.UnitTests.csproj.vspscc └── Properties │ └── AssemblyInfo.cs ├── SilverlightCompatibility ├── .gitignore ├── SilverlightCompatibility.csproj.vspscc ├── HybridDictionary.cs ├── HashSet.cs ├── INotifyPropertyChanging.cs ├── Properties │ └── AssemblyInfo.cs └── SilverlightCompatibility.csproj ├── SilverlightTest.Web ├── .gitignore ├── SilverlightTest.Web.csproj.vspscc ├── Default.aspx.cs ├── Default.aspx ├── Default.aspx.designer.cs ├── Properties │ └── AssemblyInfo.cs ├── SilverlightTestTestPage.html └── SilverlightTestTestPage.aspx └── ContinuousLinq2.vssscc /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.suo -------------------------------------------------------------------------------- /ContinuousLinq/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/Curry1.cs: -------------------------------------------------------------------------------- 1 | ErrorGeneratingOutput -------------------------------------------------------------------------------- /ContinuousLinqSL/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /OrderBookDemo/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /SilverlightTest/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /PerformanceConsole/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /ContinuousLinqSL.UnitTests/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /SilverlightCompatibility/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.user 4 | -------------------------------------------------------------------------------- /SilverlightTest.Web/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | ClientBin 4 | *.user 5 | -------------------------------------------------------------------------------- /OrderBookDemo/Resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ismell/Continuous-LINQ/HEAD/OrderBookDemo/Resources/logo.png -------------------------------------------------------------------------------- /ContinuousLinqSL.UnitTests/Libs/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ismell/Continuous-LINQ/HEAD/ContinuousLinqSL.UnitTests/Libs/nunit.framework.dll -------------------------------------------------------------------------------- /ContinuousLinqSL.UnitTests/Libs/nunit.silverlight.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ismell/Continuous-LINQ/HEAD/ContinuousLinqSL.UnitTests/Libs/nunit.silverlight.dll -------------------------------------------------------------------------------- /ContinuousLinqSL.UnitTests/Libs/Rhino.Mocks 3.5.Silverlight.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ismell/Continuous-LINQ/HEAD/ContinuousLinqSL.UnitTests/Libs/Rhino.Mocks 3.5.Silverlight.dll -------------------------------------------------------------------------------- /OrderBookDemo/Models/Order.cs: -------------------------------------------------------------------------------- 1 | namespace ContinuousLinq.OrderBookDemo.Models 2 | { 3 | public class Order 4 | { 5 | public double Ask { get; set; } 6 | public double Bid { get; set; } 7 | public double Price { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /OrderBookDemo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SilverlightTest/Properties/AppManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ContinuousLinq2.vssscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" 10 | } 11 | -------------------------------------------------------------------------------- /ContinuousLinq/ContinuousLinq.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /OrderBookDemo/OrderBookDemo.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /ContinuousLinqSL/ContinuousLinqSL.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /SilverlightTest/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SilverlightTest/SilverlightTest.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /PerformanceConsole/PerformanceConsole.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /SilverlightTest.Web/SilverlightTest.Web.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ContinuousLinq.UnitTests.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /SilverlightCompatibility/SilverlightCompatibility.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /ContinuousLinqSL.UnitTests/ContinuousLinqSL.UnitTests.csproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /OrderBookDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Windows; 7 | 8 | namespace Tester 9 | { 10 | /// 11 | /// Interaction logic for App.xaml 12 | /// 13 | public partial class App : Application 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SilverlightTest.Web/Default.aspx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.UI; 6 | using System.Web.UI.WebControls; 7 | 8 | namespace SilverlightTest.Web 9 | { 10 | public partial class _Default : System.Web.UI.Page 11 | { 12 | protected void Page_Load(object sender, EventArgs e) 13 | { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SilverlightTest/MainPage.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/PropertyAccessNodeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Windows; 7 | 8 | namespace ContinuousLinq.UnitTests 9 | { 10 | [TestFixture] 11 | [Ignore("Not used yet")] 12 | public class PropertyAccessNodeTest 13 | { 14 | //private PropertyAccessNode _target; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SilverlightTest.Web/Default.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SilverlightTest.Web._Default" %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /OrderBookDemo/Models/OrderCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | namespace ContinuousLinq.OrderBookDemo.Models 4 | { 5 | public class OrderCollection : ObservableCollection 6 | { 7 | public OrderCollection() 8 | { 9 | Populate(); 10 | } 11 | 12 | private void Populate() 13 | { 14 | for (int i = 0; i < 25; i++) 15 | { 16 | Order o = new Order() 17 | { 18 | Ask = 12.33, 19 | Bid = 12.45, 20 | Price = 12.56 21 | }; 22 | 23 | Add(o); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /OrderBookDemo/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /SilverlightCompatibility/HybridDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Documents; 6 | using System.Windows.Ink; 7 | using System.Windows.Input; 8 | using System.Windows.Media; 9 | using System.Windows.Media.Animation; 10 | using System.Windows.Shapes; 11 | using System.Collections.Generic; 12 | 13 | namespace System.Collections.Specialized 14 | { 15 | public class HybridDictionary : Dictionary 16 | { 17 | public bool Contains(object key) 18 | { 19 | return ContainsKey(key); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /OrderBookDemo/Views/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Data; 8 | using System.Windows.Documents; 9 | using System.Windows.Input; 10 | using System.Windows.Media; 11 | using System.Windows.Media.Imaging; 12 | using System.Windows.Navigation; 13 | using System.Windows.Shapes; 14 | 15 | namespace ContinuousLinq.OrderBookDemo.Views 16 | { 17 | /// 18 | /// Interaction logic for Window1.xaml 19 | /// 20 | public partial class MainWindow : Window 21 | { 22 | public MainWindow() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SilverlightCompatibility/HashSet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Documents; 6 | using System.Windows.Ink; 7 | using System.Windows.Input; 8 | using System.Windows.Media; 9 | using System.Windows.Media.Animation; 10 | using System.Windows.Shapes; 11 | using System.Collections.Generic; 12 | 13 | namespace System.Collections.Specialized 14 | { 15 | public class HashSet : Dictionary 16 | { 17 | public bool Contains(T item) 18 | { 19 | return this.ContainsKey(item); 20 | } 21 | 22 | public void Add(T item) 23 | { 24 | this[item] = null; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/WeakEvents/ListenerStub.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.WeakEvents; 7 | using System.ComponentModel; 8 | using System.Threading; 9 | 10 | namespace ContinuousLinq.UnitTests.WeakEvents 11 | { 12 | public class ListenerStub 13 | { 14 | public int CallCount { get; set; } 15 | public object Sender { get; set; } 16 | public PropertyChangedEventArgs Args { get; set; } 17 | 18 | public void OnPropertyChanged(object sender, PropertyChangedEventArgs ea) 19 | { 20 | this.CallCount++; 21 | this.Sender = sender; 22 | this.Args = ea; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/OrderedReadOnlyContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | using System.Collections.Specialized; 7 | using System.ComponentModel; 8 | using System.Linq.Expressions; 9 | using System.Diagnostics; 10 | 11 | namespace ContinuousLinq.Collections 12 | { 13 | public abstract class OrderedReadOnlyContinuousCollection : ReadOnlyAdapterContinuousCollection 14 | where TSource : INotifyPropertyChanged 15 | { 16 | internal IComparer KeySorter { get; set; } 17 | 18 | protected internal OrderedReadOnlyContinuousCollection(IList list, PropertyAccessTree propertyAccessTree) 19 | : base(list, propertyAccessTree) 20 | { } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ContinuousLinq/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ContinuousLinq 7 | { 8 | public static class DictionaryExtensions 9 | { 10 | public static TValue GetOrCreate(this Dictionary dictionary, TKey key) where TValue : new() 11 | { 12 | return dictionary.GetOrCreate(key, () => new TValue()); 13 | } 14 | 15 | public static TValue GetOrCreate(this Dictionary dictionary, TKey key, Func valueFactory) 16 | { 17 | TValue value; 18 | if (!dictionary.TryGetValue(key, out value)) 19 | { 20 | value = valueFactory(); 21 | dictionary[key] = value; 22 | } 23 | return value; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SilverlightTest/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Documents; 8 | using System.Windows.Input; 9 | using System.Windows.Media; 10 | using System.Windows.Media.Animation; 11 | using System.Windows.Shapes; 12 | 13 | namespace SilverlightTest 14 | { 15 | public partial class MainPage : UserControl 16 | { 17 | public Model Model {get; set;} 18 | 19 | 20 | public MainPage() 21 | { 22 | InitializeComponent(); 23 | 24 | this.Model = new Model(); 25 | this.Model.IntProperty = 100; 26 | this.Model.ChildModel = new Model(); 27 | this.Model.ChildModel.IntProperty = 10; 28 | 29 | DataContext = Model; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/ReadOnlyAdapterContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ContinuousLinq 4 | { 5 | public abstract class ReadOnlyAdapterContinuousCollection : ReadOnlyContinuousCollection 6 | { 7 | protected IList Source { get; set; } 8 | 9 | internal NotifyCollectionChangedMonitor NotifyCollectionChangedMonitor { get; set; } 10 | 11 | internal ReadOnlyAdapterContinuousCollection(IList list, PropertyAccessTree propertyAccessTree) 12 | { 13 | this.Source = list; 14 | this.NotifyCollectionChangedMonitor = new NotifyCollectionChangedMonitor(propertyAccessTree, list); 15 | } 16 | 17 | internal ReadOnlyAdapterContinuousCollection(IList list) 18 | :this(list, null) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ContinuousLinq.UnitTests 8 | { 9 | static class Extensions 10 | { 11 | public static TSource[] ToArray(this IList list) 12 | { 13 | TSource[] array = new TSource[list.Count]; 14 | for(int i = 0; i(this TSource item) 21 | { 22 | return new[] {item}; 23 | } 24 | 25 | public static IEnumerator GetEnumerator(this TSource[] array) 26 | { 27 | return array.ToList().GetEnumerator(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SilverlightTest.Web/Default.aspx.designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:2.0.50727.42 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SilverlightTest.Web 12 | { 13 | 14 | 15 | public partial class _Default 16 | { 17 | 18 | /// 19 | /// form1 control. 20 | /// 21 | /// 22 | /// Auto-generated field. 23 | /// To modify move field declaration from designer file to code-behind file. 24 | /// 25 | protected global::System.Web.UI.HtmlControls.HtmlForm form1; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SilverlightCompatibility/INotifyPropertyChanging.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Documents; 6 | using System.Windows.Ink; 7 | using System.Windows.Input; 8 | using System.Windows.Media; 9 | using System.Windows.Media.Animation; 10 | using System.Windows.Shapes; 11 | using System.Collections.Generic; 12 | 13 | namespace System.ComponentModel 14 | { 15 | public class PropertyChangingEventArgs : EventArgs 16 | { 17 | public PropertyChangingEventArgs(string propertyName) 18 | { 19 | this.PropertyName = propertyName; 20 | } 21 | 22 | public string PropertyName { get; private set; } 23 | } 24 | 25 | public delegate void PropertyChangingEventHandler(object sender, PropertyChangingEventArgs e); 26 | public interface INotifyPropertyChanging 27 | { 28 | event PropertyChangingEventHandler PropertyChanging; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/DistinctTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.ComponentModel; 8 | using ContinuousLinq; 9 | using ContinuousLinq.Collections; 10 | 11 | namespace ContinuousLinq.UnitTests 12 | { 13 | [TestFixture] 14 | public class DistinctTest 15 | { 16 | private ObservableCollection _source; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _source = ClinqTestFactory.CreateSixPersonSourceWithDuplicates(); 22 | } 23 | 24 | [Test] 25 | public void Construct_Always_ReturnsReadOnlyContinuousCollection() 26 | { 27 | ReadOnlyContinuousCollection result = _source.Distinct(); 28 | Assert.IsInstanceOfType(typeof(DistinctReadOnlyContinuousCollection), result); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /OrderBookDemo/Converters/PriceConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Data; 6 | 7 | namespace ContinuousLinq.OrderBookDemo.Converters 8 | { 9 | public class PriceConverter : IValueConverter 10 | { 11 | #region IValueConverter Members 12 | 13 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 14 | { 15 | if (value != null) 16 | { 17 | double d = (double)value; 18 | return string.Format("{0:C}", d); 19 | } 20 | else 21 | return string.Empty; 22 | } 23 | 24 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 25 | { 26 | throw new NotImplementedException(); 27 | } 28 | 29 | #endregion 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ContinuousLinq/Reactive/DependsOnMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Linq.Expressions; 7 | 8 | namespace ContinuousLinq.Reactive 9 | { 10 | public class DependsOnMethod : ReactiveMethod where T : class, INotifyPropertyChanged 11 | { 12 | #region Constructor 13 | 14 | internal DependsOnMethod(Action callback) : base(callback, callback) 15 | { 16 | } 17 | 18 | #endregion 19 | 20 | #region Methods 21 | 22 | public DependsOnMethod OnChanged(Expression> propertyAccessor) 23 | { 24 | Register(propertyAccessor, FireOn.PropertyChanged); 25 | return this; 26 | } 27 | 28 | public DependsOnMethod OnChanging(Expression> propertyAccessor) { 29 | Register(propertyAccessor, FireOn.PropertyChanging); 30 | return this; 31 | } 32 | 33 | #endregion 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/ReadOnlyTwoCollectionOperationContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ContinuousLinq 4 | { 5 | public abstract class ReadOnlyTwoCollectionOperationContinuousCollection : ReadOnlyContinuousCollection 6 | { 7 | protected IList First { get; set; } 8 | protected IList Second { get; set; } 9 | 10 | internal NotifyCollectionChangedMonitor NotifyCollectionChangedMonitorForFirst { get; set; } 11 | internal NotifyCollectionChangedMonitor NotifyCollectionChangedMonitorForSecond { get; set; } 12 | 13 | internal ReadOnlyTwoCollectionOperationContinuousCollection(IList first, IList second) 14 | { 15 | this.First = first; 16 | this.NotifyCollectionChangedMonitorForFirst = new NotifyCollectionChangedMonitor(null, first); 17 | 18 | this.Second = second; 19 | this.NotifyCollectionChangedMonitorForSecond = new NotifyCollectionChangedMonitor(null, second); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /OrderBookDemo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:2.0.50727.3053 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ContinuousLinq.OrderBookDemo.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/PassThroughReadOnlyContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.ComponentModel; 7 | using System.Collections.Specialized; 8 | 9 | namespace ContinuousLinq 10 | { 11 | public class PassThroughReadOnlyContinuousCollection : ReadOnlyAdapterContinuousCollection 12 | { 13 | public PassThroughReadOnlyContinuousCollection(IList list) 14 | : base(list, null) 15 | { 16 | this.NotifyCollectionChangedMonitor.CollectionChanged += OnSourceCollectionChanged; 17 | } 18 | 19 | void OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) 20 | { 21 | RefireCollectionChanged(args); 22 | } 23 | 24 | public override int Count 25 | { 26 | get { return this.Source.Count; } 27 | } 28 | 29 | public override TSource this[int index] 30 | { 31 | get { return this.Source[index]; } 32 | set { throw new AccessViolationException(); } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ContinuousLinq/Aggregation/PausedAggregation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Linq.Expressions; 7 | using System.Collections.Specialized; 8 | 9 | namespace ContinuousLinq.Aggregates 10 | { 11 | /// 12 | /// Usage pattern: When you wish to guard a block of code such that no background re-aggregation of data 13 | /// takes place during that block of code, you can enclose your block in a using as follows: 14 | /// 15 | /// using (PausedAggregation p = new PausedAggregation) { ... guarded code ... } 16 | /// 17 | /// 18 | public class PausedAggregation : IDisposable 19 | { 20 | private bool _wasDisposed; 21 | 22 | public PausedAggregation() 23 | { 24 | ContinuousValue.GlobalPause(); 25 | } 26 | 27 | #region IDisposable Members 28 | 29 | public void Dispose() 30 | { 31 | if (!_wasDisposed) 32 | { 33 | ContinuousValue.GlobalResume(); 34 | _wasDisposed = true; 35 | } 36 | } 37 | #endregion 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/AsReadOnlyTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.ComponentModel; 8 | using ContinuousLinq; 9 | 10 | namespace ContinuousLinq.UnitTests 11 | { 12 | [TestFixture] 13 | public class AsReadOnlyTest 14 | { 15 | private ObservableCollection _source; 16 | 17 | [SetUp] 18 | public void Setup() 19 | { 20 | _source = ClinqTestFactory.CreateTwoPersonSource(); 21 | } 22 | 23 | [Test] 24 | public void AsReadOnly_SourceHasItems_ReturnsPassThroughReadOnlyContinuousCollection() 25 | { 26 | ReadOnlyContinuousCollection result = _source.AsReadOnly(); 27 | Assert.IsNotNull(result); 28 | Assert.IsInstanceOfType(typeof(PassThroughReadOnlyContinuousCollection), result); 29 | } 30 | 31 | [Test] 32 | public void AsReadOnly_SourceHasItems_AllItemsInResult() 33 | { 34 | ReadOnlyContinuousCollection result = _source.AsReadOnly(); 35 | for (int i = 0; i < _source.Count; i++) 36 | { 37 | Assert.AreEqual(_source[i], result[i]); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/ContinuousLinqHelperException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | using System.Collections.Specialized; 7 | using System.ComponentModel; 8 | using System.Linq.Expressions; 9 | using ContinuousLinq.Expressions; 10 | using System.Diagnostics; 11 | using System.Text.RegularExpressions; 12 | 13 | namespace ContinuousLinq 14 | { 15 | public class ContinuousLinqHelperException : Exception 16 | { 17 | const string MESSAGE = "This exception's stack trace shows where the Continuous Linq query was declared. Check the inner exception for actual error"; 18 | 19 | public ContinuousLinqHelperException(StackTrace stackTraceOfCollectionDeclaration, Exception actualException) 20 | : base(MESSAGE, actualException) 21 | { 22 | this.StackTraceOfCollectionDeclaration = stackTraceOfCollectionDeclaration; 23 | } 24 | 25 | public StackTrace StackTraceOfCollectionDeclaration { get; private set; } 26 | 27 | public override string StackTrace 28 | { 29 | get 30 | { 31 | string stackTrace = this.StackTraceOfCollectionDeclaration.ToString(); 32 | 33 | stackTrace = Regex.Replace(stackTrace, @"at\s+ContinuousLinq\..*?\n", string.Empty); 34 | return stackTrace; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ContinuousContainsTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using ContinuousLinq.Aggregates; 8 | 9 | namespace ContinuousLinq.UnitTests 10 | { 11 | [TestFixture] 12 | public class ContinuousContainsTest 13 | { 14 | private ObservableCollection _source; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | _source = ClinqTestFactory.CreateTwoPersonSource(); 20 | } 21 | 22 | [Test] 23 | public void Contains_Test() 24 | { 25 | Person p = _source[0]; 26 | ContinuousValue hasPerson = _source.ContinuousContains(p); 27 | 28 | Assert.IsTrue(hasPerson.CurrentValue); 29 | _source.Remove(p); 30 | Assert.IsFalse(hasPerson.CurrentValue); 31 | } 32 | 33 | [Test] 34 | public void Contains_Test_AfterEffect() 35 | { 36 | Person p = _source[0]; 37 | bool personAE = false; 38 | ContinuousValue hasPerson = _source.ContinuousContains(p, val => personAE = val); 39 | 40 | Assert.IsTrue(hasPerson.CurrentValue); 41 | Assert.IsTrue(personAE); 42 | _source.Remove(p); 43 | Assert.IsFalse(hasPerson.CurrentValue); 44 | Assert.IsFalse(personAE); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/ParameterNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.ComponentModel; 8 | using System.Windows; 9 | using System.Collections; 10 | 11 | namespace ContinuousLinq 12 | { 13 | internal class ParameterNode : PropertyAccessTreeNode 14 | { 15 | private Type _type; 16 | public override Type Type 17 | { 18 | get { return _type; } 19 | } 20 | 21 | public string Name { get; private set; } 22 | 23 | public override bool IsRedundantVersion(PropertyAccessTreeNode other) 24 | { 25 | var otherAsParameterNode = other as ParameterNode; 26 | return otherAsParameterNode != null && otherAsParameterNode != this && this.Name == otherAsParameterNode.Name; 27 | } 28 | 29 | public ParameterNode(Type type, string name) 30 | { 31 | _type = type; 32 | this.Name = name; 33 | } 34 | 35 | public override SubscriptionNode CreateSubscription(INotifyPropertyChanged parameter) 36 | { 37 | var subscriptionNode = new SubscriptionNode() 38 | { 39 | AccessNode = this 40 | }; 41 | 42 | SubscribeToChildren(subscriptionNode, parameter); 43 | subscriptionNode.Subject = parameter; 44 | 45 | return subscriptionNode; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/SubscriptionTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.ComponentModel; 8 | using System.Windows; 9 | using System.Collections; 10 | 11 | namespace ContinuousLinq 12 | { 13 | public class SubscriptionTree 14 | { 15 | public INotifyPropertyChanged Parameter { get; set; } 16 | 17 | internal List Children { get; set; } 18 | 19 | public event Action PropertyChanged; 20 | 21 | internal SubscriptionTree(INotifyPropertyChanged parameter, List children) 22 | { 23 | this.Parameter = parameter; 24 | this.Children = children; 25 | 26 | SubscribeToEntireTree(this.Children); 27 | } 28 | 29 | internal void SubscribeToEntireTree(List nodes) 30 | { 31 | foreach (SubscriptionNode child in nodes) 32 | { 33 | child.PropertyChanged += OnNodeInTreePropertyChanged; 34 | if (child.Children != null) 35 | { 36 | SubscribeToEntireTree(child.Children); 37 | } 38 | } 39 | } 40 | 41 | private void OnNodeInTreePropertyChanged() 42 | { 43 | if (PropertyChanged == null) 44 | return; 45 | PropertyChanged(this); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SilverlightTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SilverlightTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SilverlightTest")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("badf2234-0d12-4133-a644-53aa9fcb450f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/ConstantNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.ComponentModel; 8 | using System.Windows; 9 | using System.Collections; 10 | 11 | namespace ContinuousLinq 12 | { 13 | internal class ConstantNode : PropertyAccessTreeNode 14 | { 15 | public INotifyPropertyChanged Value { get; set; } 16 | 17 | public override Type Type 18 | { 19 | get { return this.Value.GetType(); } 20 | } 21 | 22 | public ConstantNode(INotifyPropertyChanged value) 23 | { 24 | this.Value = value; 25 | } 26 | 27 | public override bool IsRedundantVersion(PropertyAccessTreeNode other) 28 | { 29 | ConstantNode otherAsConstantNode = other as ConstantNode; 30 | if (otherAsConstantNode == null) 31 | return false; 32 | 33 | return other != this && otherAsConstantNode.Value == this.Value; 34 | } 35 | 36 | public override SubscriptionNode CreateSubscription(INotifyPropertyChanged parameter) 37 | { 38 | var subscriptionNode = new SubscriptionNode() 39 | { 40 | AccessNode = this 41 | }; 42 | SubscribeToChildren(subscriptionNode, parameter); 43 | 44 | subscriptionNode.Subject = this.Value; 45 | 46 | return subscriptionNode; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /SilverlightTest.Web/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SilverlightTest.Web")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SilverlightTest.Web")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /SilverlightCompatibility/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SilverlightCompatibility")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("SilverlightCompatibility")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3a1ae22d-9684-4ab1-9713-7f441613cedb")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ContinuousLinqSL.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ContinuousLinqSL.UnitTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("ContinuousLinqSL.UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("46e93af9-4fe7-4a82-b3c5-b0110c6a8745")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ContinuousCountTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using ContinuousLinq.Aggregates; 8 | 9 | namespace ContinuousLinq.UnitTests 10 | { 11 | [TestFixture] 12 | public class ContinuousCountTest 13 | { 14 | private ObservableCollection _source; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | _source = ClinqTestFactory.CreateTwoPersonSource(); 20 | } 21 | 22 | [Test] 23 | public void Count_ImmediatelyAfterConstruction_SumCompleted() 24 | { 25 | ContinuousValue count = _source.ContinuousCount(); 26 | 27 | Assert.AreEqual(2, count.CurrentValue); 28 | } 29 | 30 | [Test] 31 | public void Count_AddingValueToCollection_CountUpdated() 32 | { 33 | ContinuousValue count = _source.ContinuousCount(); 34 | _source.Add(new Person()); 35 | 36 | Assert.AreEqual(3, count.CurrentValue); 37 | } 38 | 39 | [Test] 40 | public void Count_AddingValueToCollection_AfterEffect() 41 | { 42 | int modCount = 0; 43 | ContinuousValue count = _source.ContinuousCount(c => modCount = c); 44 | _source.Add(new Person()); 45 | 46 | Assert.AreEqual(3, count.CurrentValue); 47 | Assert.AreEqual(modCount, count.CurrentValue); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /PerformanceConsole/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PerformanceConsole")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PerformanceConsole")] 13 | [assembly: AssemblyCopyright("Copyright © 2008")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7ddcf7b8-af29-4d6e-8480-0c08c194ef7d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ContinuousLinq.UnitTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ContinuousLinq.UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © 2008")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b8b324b6-2f48-4574-bcb6-a82b9ca8f54c")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ContinuousLinqSL/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ContinuousLinqSL")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("ContinuousLinqSL")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b88bc342-6a3c-4f09-8cbd-72fbc1eb70cb")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("2.0.0.0")] 35 | [assembly: AssemblyFileVersion("2.0.0.0")] 36 | 37 | [assembly: InternalsVisibleTo("ContinuousLinqSL.UnitTests")] -------------------------------------------------------------------------------- /OrderBookDemo/Models/Vwap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Text; 6 | using ContinuousLinq; 7 | using ContinuousLinq.Aggregates; 8 | using System.Collections.ObjectModel; 9 | using System.ComponentModel; 10 | 11 | namespace ContinuousLinq.OrderBookDemo.Models 12 | { 13 | public static class Vwap 14 | { 15 | public static ContinuousValue ContinuousVwap( 16 | this ReadOnlyContinuousCollection input, 17 | Func priceSelector, 18 | Func quantitySelector, 19 | Action afterEffect) 20 | where T:INotifyPropertyChanged 21 | { 22 | return new ContinuousValue(input, null, 23 | (list, selector) => ComputeVwap(list, priceSelector, quantitySelector), afterEffect); 24 | } 25 | 26 | public static double ComputeVwap(IList list, Func priceSelector, 27 | Func quantitySelector) 28 | { 29 | int count = list.Count; 30 | double weightedPrice = 0.0; 31 | int totalQuantity = 0; 32 | 33 | for (int x = 0; x < count; x++) 34 | { 35 | weightedPrice += priceSelector(list[x]) * 36 | quantitySelector(list[x]); 37 | totalQuantity += quantitySelector(list[x]); 38 | } 39 | 40 | double vwap = weightedPrice / totalQuantity; 41 | return vwap; 42 | } 43 | 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ContinuousLinq/Reactive/BridgeMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | 9 | namespace ContinuousLinq.Reactive 10 | { 11 | public class BridgeMethod : ReactiveMethod where T : ReactiveObject { 12 | 13 | public static BridgeMethod Create(Expression> propertyAccessor) { 14 | MemberExpression memberExpression = ExpressionPropertyAnalyzer.UnwrapLambda(propertyAccessor); 15 | 16 | if (!(memberExpression.Expression is ParameterExpression)) { 17 | throw new InvalidOperationException("Extended Properties are not allowed."); 18 | } 19 | 20 | var name = ExpressionPropertyAnalyzer.ExtractPropertyName(propertyAccessor); 21 | 22 | Action changedCallback = me => me.OnPropertyChanged(name); 23 | Action changingCallback = me => me.OnPropertyChanging(name); 24 | 25 | var method = new BridgeMethod(changingCallback, changedCallback); 26 | 27 | return method; 28 | } 29 | 30 | private BridgeMethod(Action onPropertyChanging, Action onPropertyChanged) 31 | : base(onPropertyChanging, onPropertyChanged) { 32 | 33 | } 34 | 35 | public BridgeMethod With(Expression> propertyAccessor) { 36 | Register(propertyAccessor, FireOn.PropertyChanging | FireOn.PropertyChanged); 37 | return this; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/PassThroughReadOnlyContinuousCollectionTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.Collections.Specialized; 8 | using System.Collections; 9 | 10 | namespace ContinuousLinq.UnitTests 11 | { 12 | [TestFixture] 13 | public class PassThroughReadOnlyContinuousCollectionTest 14 | { 15 | private ObservableCollection _source; 16 | private PassThroughReadOnlyContinuousCollection _target; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _source = ClinqTestFactory.CreateTwoPersonSource(); 22 | _target = new PassThroughReadOnlyContinuousCollection(_source); 23 | } 24 | 25 | [Test] 26 | public void GetByIndex_ItemsInSource_RetrievesAllItems() 27 | { 28 | for (int i = 0; i < _source.Count; i++) 29 | { 30 | Assert.AreEqual(_source[i], _target[i]); 31 | } 32 | } 33 | 34 | [Test] 35 | public void AddItemToSource_NewItem_FiresPropertyChanged() 36 | { 37 | int callCount = 0; 38 | _target.CollectionChanged += (sender, args) => callCount++; 39 | 40 | _source.Add(new Person()); 41 | 42 | Assert.AreEqual(1, callCount); 43 | } 44 | 45 | [Test] 46 | public void Count_SourceHasItems_SameAsSource() 47 | { 48 | Assert.AreEqual(_source.Count, _target.Count); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /PerformanceConsole/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace PerformanceConsole 7 | { 8 | class Program 9 | { 10 | static void Main(string[] args) 11 | { 12 | PerformanceTest performanceTest = new PerformanceTest(); 13 | //performanceTest.GroupJoin(); 14 | //performanceTest.MySkipListVsLomontLookups(); 15 | //performanceTest.MySkipListVsLomontAdds(); 16 | //performanceTest.SkipListVsSortedDictionaryAdds(); 17 | //performanceTest.SkipListVsSortedDictionaryLookups(); 18 | //performanceTest.LlrbtVsSortedDictionaryAdds(); 19 | //performanceTest.LlrbtVsSortedDictionaryLookups(); 20 | //performanceTest.RecursiveFunctionVsStack(); 21 | //performanceTest.CompareQueryCreation(); 22 | //performanceTest.GetInterfaceTest(); 23 | //performanceTest.MemoryTest(); 24 | //performanceTest.SortingTest(); 25 | //performanceTest.TestDynamicProperty(); 26 | //performanceTest.TestDynamicInvoke(); 27 | //performanceTest.SelectTest(); 28 | //performanceTest.SelectLinearUpdateTest(); 29 | //performanceTest.SelectUnrelatedPropertyLinearUpdateTest(); 30 | //performanceTest.WhereTest(); 31 | //performanceTest.ContinuousSumWithoutPausing(); 32 | //performanceTest.ContinuousSumWithPausing(); 33 | //performanceTest.TakeTest(); 34 | //performanceTest.SkipTest(); 35 | performanceTest.SkipTakeCombineAssertTest(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ContinuousLinq/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ContinuousLinq")] 9 | [assembly: AssemblyDescription("A library to facilitate real-time, streaming LINQ queries")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ContinuousLinq")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("56947a02-6fb3-4109-93dd-bb6d7a877206")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2.2.0.1")] 36 | [assembly: AssemblyFileVersion("2.2.0.1")] 37 | 38 | 39 | //#if DEBUG 40 | [assembly: InternalsVisibleTo("ContinuousLinq.UnitTests")] 41 | //#endif 42 | -------------------------------------------------------------------------------- /ContinuousLinq/Reactive/DependsOn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | 9 | namespace ContinuousLinq.Reactive 10 | { 11 | internal interface IDependsOn 12 | { 13 | void CreateSubscriptions(INotifyPropertyChanged subject, ref List listToAppendTo); 14 | } 15 | 16 | public class DependsOn : IDependsOn where T : ReactiveObject 17 | { 18 | #region Constructor 19 | 20 | internal DependsOn() 21 | { 22 | this.Methods = new List>(); 23 | } 24 | 25 | #endregion 26 | 27 | #region Properties 28 | 29 | private List> Methods { get; set; } 30 | 31 | #endregion 32 | 33 | #region Methods 34 | 35 | public void CreateSubscriptions(INotifyPropertyChanged subject, ref List listToAppendTo) 36 | { 37 | foreach (var dependsOnMethod in this.Methods) 38 | { 39 | dependsOnMethod.CreateSubscriptions(subject, ref listToAppendTo); 40 | } 41 | } 42 | 43 | public DependsOnMethod Call(Action callback) 44 | { 45 | var dependsOnMethod = new DependsOnMethod(callback); 46 | this.Methods.Add(dependsOnMethod); 47 | 48 | return dependsOnMethod; 49 | } 50 | 51 | public BridgeMethod Bridge(Expression> propertyAccessor) { 52 | var bridgeMethod = BridgeMethod.Create(propertyAccessor); 53 | 54 | this.Methods.Add(bridgeMethod); 55 | 56 | return bridgeMethod; 57 | } 58 | 59 | #endregion 60 | } 61 | } -------------------------------------------------------------------------------- /ContinuousLinq/Collections/GroupedReadOnlyContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.Specialized; 6 | 7 | namespace ContinuousLinq.Collections 8 | { 9 | public class GroupedReadOnlyContinuousCollection 10 | : ReadOnlyAdapterContinuousCollection, IGrouping 11 | { 12 | internal ContinuousCollection InternalCollection 13 | { 14 | get { return (ContinuousCollection)this.Source; } 15 | } 16 | 17 | public GroupedReadOnlyContinuousCollection(TKey key) 18 | : base(new ContinuousCollection(), null) 19 | { 20 | this.Key = key; 21 | this.NotifyCollectionChangedMonitor.CollectionChanged += OnSourceCollectionChanged; 22 | } 23 | 24 | void OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) 25 | { 26 | RefireCollectionChanged(args); 27 | } 28 | 29 | #region IGrouping Members 30 | 31 | private TKey _key; 32 | public TKey Key 33 | { 34 | get { return _key; } 35 | set 36 | { 37 | if (EqualityComparer.Default.Equals(value, _key)) 38 | return; 39 | 40 | _key = value; 41 | OnPropertyChanged("Key"); 42 | } 43 | } 44 | 45 | #endregion 46 | 47 | public override TSource this[int index] 48 | { 49 | get { return this.Source[index]; } 50 | set { throw new AccessViolationException(); } 51 | } 52 | 53 | public override int Count 54 | { 55 | get { return this.Source.Count; } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/Curry.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#v3.5"#> 2 | 3 | // 4 | // This code was generated by a tool. Any changes made manually will be lost 5 | // the next time this code is regenerated. 6 | // 7 | using System; 8 | namespace ContinuousLinq.Expressions 9 | { 10 | public static class Partials 11 | { 12 | 13 | <#for(int iOpen=1;iOpen<=20;iOpen++){#><#for(int iClose=1;iClose<=19-iOpen;iClose++){#> 14 | public static Func<<#FormatRange("T{0}, ",1, iOpen); #>TReturn> Partial<<#FormatRange("TC{0}, ", 1, iClose); #><#FormatRange("T{0}, ", 1, iOpen); #>TReturn>(this Func<<# FormatRange("TC{0}, ",1, iClose); #><# FormatRange("T{0}, ",1, iOpen); #>TReturn> function, <# FormatRange("TC{0} tc{0}", ", ", 1, iClose); #>) 15 | { 16 | return (<#FormatRange("t{0}", ", ", 1, iOpen); #>) => function(<#FormatRange("tc{0}", ", ", 1, iClose); #>, <#FormatRange("t{0}", ", ", 1, iOpen); #>); 17 | } 18 | <#}#><#}#> 19 | 20 | } 21 | } 22 | 23 | namespace System 24 | { 25 | <#for(int i=5;i<=20;i++){#>public delegate TResult FuncTResult>(<#FormatRange("T{0} t{0}", ", ", 1, i);#>); 26 | <#}#> 27 | 28 | <#for(int i=5;i<=20;i++){#>public delegate void Action>(<#FormatRange("T{0} t{0}", ", ", 1, i);#>); 29 | <#}#> 30 | } 31 | 32 | <#+ 33 | private void FormatRange(string itemFormatString, int start, int end) 34 | { 35 | for(int i = start; i <= end; i++) 36 | { 37 | this.Write(string.Format(itemFormatString, i)); 38 | } 39 | } 40 | 41 | private void FormatRange(string itemFormatString, string separatorFormatString, int start, int end) 42 | { 43 | for(int i = start; i <= end; i++) 44 | { 45 | this.Write(string.Format(itemFormatString, i)); 46 | if(i != end) 47 | { 48 | this.Write(string.Format(separatorFormatString, i)); 49 | } 50 | } 51 | } 52 | #> -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ReferenceCountTrackerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | 8 | namespace ContinuousLinq.UnitTests 9 | { 10 | [TestFixture] 11 | public class ReferenceCountTrackerTest 12 | { 13 | private ReferenceCountTracker _target; 14 | 15 | [SetUp] 16 | public void Setup() 17 | { 18 | _target = new ReferenceCountTracker(); 19 | } 20 | 21 | [Test] 22 | public void Add_ItemNotCurrentlyBeingTracked_ReturnsTrue() 23 | { 24 | Person person = new Person(); 25 | Assert.IsTrue(_target.Add(person)); 26 | } 27 | 28 | [Test] 29 | public void Add_ItemCurrentlyBeingTracked_ReturnsFalse() 30 | { 31 | Person person = new Person(); 32 | _target.Add(person); 33 | Assert.IsFalse(_target.Add(person)); 34 | } 35 | 36 | [Test] 37 | public void Remove_ItemCurrentlyBeingTrackedAndLastReferenceCount_ReturnsTrue() 38 | { 39 | Person person = new Person(); 40 | _target.Add(person); 41 | Assert.IsTrue(_target.Remove(person)); 42 | } 43 | 44 | [Test] 45 | public void Remove_ItemReferenceCountIsTwo_ReturnsFalse() 46 | { 47 | Person person = new Person(); 48 | _target.Add(person); 49 | _target.Add(person); 50 | Assert.IsFalse(_target.Remove(person)); 51 | } 52 | 53 | [Test] 54 | public void Clear_ItemReferenceCountIsTwo_NextAddReturnsTrue() 55 | { 56 | Person person = new Person(); 57 | _target.Add(person); 58 | _target.Add(person); 59 | 60 | _target.Clear(); 61 | 62 | Assert.IsTrue(_target.Add(person)); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /SilverlightTest/Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Documents; 6 | using System.Windows.Ink; 7 | using System.Windows.Input; 8 | using System.Windows.Media; 9 | using System.Windows.Media.Animation; 10 | using System.Windows.Shapes; 11 | using ContinuousLinq.Reactive; 12 | 13 | namespace SilverlightTest 14 | { 15 | public class Model : ReactiveObject 16 | { 17 | private int _intProperty; 18 | public int IntProperty 19 | { 20 | get { return _intProperty; } 21 | set 22 | { 23 | if (value == _intProperty) 24 | return; 25 | 26 | OnPropertyChanging("IntProperty"); 27 | _intProperty = value; 28 | OnPropertyChanged("IntProperty"); 29 | } 30 | } 31 | 32 | private Model _childModel; 33 | public Model ChildModel 34 | { 35 | get { return _childModel; } 36 | set 37 | { 38 | if (value == _childModel) 39 | return; 40 | 41 | OnPropertyChanging("ChildModel"); 42 | _childModel = value; 43 | OnPropertyChanged("ChildModel"); 44 | } 45 | } 46 | 47 | static Model() 48 | { 49 | var dependsOn = Register(); 50 | 51 | dependsOn.Call(obj => obj.OnIntPropertyChanged()) 52 | .OnChanged(obj => obj.IntProperty); 53 | 54 | dependsOn.Call(obj => obj.OnChildModelIntPropertyChanged()) 55 | .OnChanged(obj => obj.ChildModel.IntProperty); 56 | } 57 | 58 | private void OnIntPropertyChanged() 59 | { 60 | int a = 0; 61 | a++; 62 | } 63 | 64 | private void OnChildModelIntPropertyChanged() 65 | { 66 | int a = 0; 67 | a++; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/ThenByReadOnlyContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | using System.Collections.Specialized; 7 | using System.ComponentModel; 8 | using System.Linq.Expressions; 9 | using System.Diagnostics; 10 | 11 | namespace ContinuousLinq.Collections 12 | { 13 | internal class ThenByReadOnlyContinuousCollection : 14 | SortingReadOnlyContinuousCollection 15 | where TSource : INotifyPropertyChanged 16 | where TKey : IComparable 17 | { 18 | public ThenByReadOnlyContinuousCollection(OrderedReadOnlyContinuousCollection list, 19 | Expression> keySelectorExpression, 20 | bool descending) 21 | : base(list, keySelectorExpression, descending) 22 | { 23 | } 24 | 25 | protected override void SetComparerChain(IComparer compareFunc) 26 | { 27 | OrderedReadOnlyContinuousCollection previous = this.Source as OrderedReadOnlyContinuousCollection; 28 | if (previous != null) 29 | { 30 | this.KeySorter = new ChainComparer(previous.KeySorter, compareFunc); 31 | } 32 | } 33 | 34 | private class ChainComparer : IComparer 35 | { 36 | private readonly IComparer _previousComparer; 37 | private readonly IComparer _currentComparer; 38 | 39 | public ChainComparer(IComparer previousComparer, IComparer currentComparer) 40 | { 41 | _previousComparer = previousComparer; 42 | _currentComparer = currentComparer; 43 | } 44 | 45 | public int Compare(TSource x, TSource y) 46 | { 47 | int result = _previousComparer.Compare(x, y); 48 | if (result != 0) 49 | return result; 50 | return _currentComparer.Compare(x, y); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/DynamicPropertyTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.Expressions; 7 | 8 | namespace ContinuousLinq.UnitTests 9 | { 10 | [TestFixture] 11 | public class DynamicPropertyTest 12 | { 13 | private DynamicProperty _target; 14 | private Person _person; 15 | [SetUp] 16 | public void Setup() 17 | { 18 | _person = new Person(); 19 | } 20 | 21 | [TearDown] 22 | public void TearDown() 23 | { 24 | DynamicProperty.ClearCaches(); 25 | } 26 | 27 | [Test] 28 | public void GetValue_PropertyIsValueType_GetsBoxedAndReturnsCorrectValue() 29 | { 30 | _target = DynamicProperty.Create(typeof(Person), "Age"); 31 | _person.Age = 100; 32 | object age = _target.GetValue(_person); 33 | Assert.AreEqual(100, age); 34 | } 35 | 36 | [Test] 37 | public void GetValue_PropertyIsReferenceType_GetsBoxedAndReturnsCorrectValue() 38 | { 39 | Person brother = new Person(); 40 | _person.Brother = brother; 41 | 42 | _target = DynamicProperty.Create(typeof(Person), "Brother"); 43 | object brotherDynamic = _target.GetValue(_person); 44 | Assert.AreSame(brother, brotherDynamic); 45 | } 46 | 47 | [Test] 48 | public void Create_CalledTwice_ReturnsCachedProperty() 49 | { 50 | DynamicProperty one = DynamicProperty.Create(typeof(Person), "Brother"); 51 | DynamicProperty two = DynamicProperty.Create(typeof(Person), "Brother"); 52 | 53 | Assert.AreSame(one, two); 54 | } 55 | 56 | [Test] 57 | public void Create_CalledTwiceWithPropertyInfo_ReturnsCachedProperty() 58 | { 59 | DynamicProperty one = DynamicProperty.Create(typeof(Person).GetProperty("Brother")); 60 | DynamicProperty two = DynamicProperty.Create(typeof(Person).GetProperty("Brother")); 61 | 62 | Assert.AreSame(one, two); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ThenByTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.Diagnostics; 8 | using System.Collections; 9 | 10 | namespace ContinuousLinq.UnitTests 11 | { 12 | [TestFixture] 13 | public class ThenByTest 14 | { 15 | private ObservableCollection _source; 16 | 17 | [SetUp] 18 | public void SetUp() 19 | { 20 | _source = ClinqTestFactory.CreateSixPersonSource(); 21 | _source[1].Age = 20; // same as _source[2].age 22 | _source[2].Age = 20; 23 | _source[1].Name = "Zoolander"; 24 | _source[2].Name = "Alfonse"; 25 | } 26 | 27 | [Test] 28 | public void Sort_ThenBy_CountRemainsTheSame() 29 | { 30 | ReadOnlyContinuousCollection output = 31 | from person in _source 32 | orderby person.Age, person.Name 33 | select person; 34 | 35 | Assert.AreEqual(_source.Count, output.Count); 36 | } 37 | 38 | [Test] 39 | public void Sort_ThenBy_SortedItemsAreInProperIndexes() 40 | { 41 | ReadOnlyContinuousCollection output = 42 | from person in _source 43 | orderby person.Age, person.Name 44 | select person; 45 | 46 | Assert.AreEqual(output[0].Age, 0); 47 | Assert.AreEqual(output[1].Age, 20); 48 | Assert.AreEqual(output[2].Age, 20); 49 | // output IDX 1 should be alfonse 50 | // output IDX 2 should be zoolander 51 | 52 | Assert.AreEqual(output[1].Name, "Alfonse"); 53 | Assert.AreEqual(output[2].Name, "Zoolander"); 54 | } 55 | 56 | [Test] 57 | public void StandardClinqBehavior() 58 | { 59 | IEnumerable list = _source; 60 | 61 | var output = from person in list 62 | orderby person.Age, person.Name 63 | select person; 64 | 65 | Assert.AreEqual(_source.Count, output.Count()); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/PropertyAccessTreeNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.ComponentModel; 8 | using System.Windows; 9 | using System.Collections; 10 | 11 | namespace ContinuousLinq 12 | { 13 | internal abstract class PropertyAccessTreeNode 14 | { 15 | 16 | public abstract bool IsRedundantVersion(PropertyAccessTreeNode other); 17 | public abstract Type Type { get; } 18 | 19 | public List Children { get; set; } 20 | 21 | public bool DoesEntireSubtreeSupportINotifyPropertyChanging 22 | { 23 | get 24 | { 25 | if (this.Children.Count == 0) 26 | return true; 27 | 28 | if (!typeof(INotifyPropertyChanging).IsAssignableFrom(this.Type)) 29 | return false; 30 | 31 | for (int i = 0; i < this.Children.Count; i++) 32 | { 33 | if (!this.Children[i].DoesEntireSubtreeSupportINotifyPropertyChanging) 34 | return false; 35 | } 36 | 37 | return true; 38 | } 39 | } 40 | 41 | public PropertyAccessTreeNode() 42 | { 43 | this.Children = new List(); 44 | } 45 | 46 | public abstract SubscriptionNode CreateSubscription(INotifyPropertyChanged parent); 47 | 48 | protected void SubscribeToChildren(SubscriptionNode subscriptionNode, INotifyPropertyChanged parameter) 49 | { 50 | for (int i = 0; i < this.Children.Count; i++) 51 | { 52 | PropertyAccessTreeNode child = this.Children[i]; 53 | if (child.Children.Count == 0) 54 | continue; 55 | 56 | SubscriptionNode childSubscriptionNode = child.CreateSubscription(parameter); 57 | 58 | if (subscriptionNode.Children == null) 59 | subscriptionNode.Children = new List(); 60 | 61 | subscriptionNode.Children.Add(childSubscriptionNode); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/WeakEvents/WeakEventHandlerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.WeakEvents; 7 | using System.ComponentModel; 8 | 9 | namespace ContinuousLinq.UnitTests.WeakEvents 10 | { 11 | [TestFixture] 12 | public class WeakEventHandlerTest 13 | { 14 | [Test] 15 | public void Register_ListenerSetToNullAndGarbageCollected_ListenerSetToNull() 16 | { 17 | EventListenerStub listener = new EventListenerStub(); 18 | WeakReference listenerRef = new WeakReference(listener); 19 | 20 | Person person = new Person(); 21 | 22 | WeakEventHandler weakEventHandler = WeakPropertyChangedEventHandler.Register( 23 | person, 24 | (s, eh) => s.PropertyChanged -= eh, 25 | listener, 26 | (me, sender, ea) => me.OnPropertyChanged(sender, ea)); 27 | 28 | listener = null; 29 | GC.Collect(); 30 | 31 | Assert.IsFalse(listenerRef.IsAlive); 32 | } 33 | 34 | [Test] 35 | public void FirePropertyChangedEvent_Always_CallsCallback() 36 | { 37 | EventListenerStub listener = new EventListenerStub(); 38 | 39 | Person person = new Person(); 40 | 41 | WeakEventHandler weakEventHandler = WeakPropertyChangedEventHandler.Register( 42 | person, 43 | (s, eh) => s.PropertyChanged -= eh, 44 | listener, 45 | (me, sender, ea) => me.OnPropertyChanged(sender, ea)); 46 | 47 | person.Name = "Bob"; 48 | 49 | Assert.AreEqual(1, listener.EventHandlerCallCount); 50 | Assert.AreEqual("Name", listener.LastPropertyChanged); 51 | } 52 | } 53 | 54 | public class EventListenerStub 55 | { 56 | public int EventHandlerCallCount { get; set; } 57 | 58 | public string LastPropertyChanged { get; private set; } 59 | 60 | public void OnPropertyChanged(object sender, PropertyChangedEventArgs ea) 61 | { 62 | this.EventHandlerCallCount++; 63 | this.LastPropertyChanged = ea.PropertyName; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/WeakEvents/WeakPropertyBridgeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using ContinuousLinq.WeakEvents; 6 | using NUnit.Framework; 7 | 8 | namespace ContinuousLinq.UnitTests.WeakEvents 9 | { 10 | [TestFixture] 11 | public class WeakPropertyBridgeTest 12 | { 13 | private WeakPropertyBridge _target; 14 | 15 | private ListenerStub _listener; 16 | private Person _person; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _person = new Person(); 22 | _target = new WeakPropertyBridge(_person); 23 | _listener = new ListenerStub(); 24 | } 25 | 26 | [Test] 27 | public void AddListenerAndChangeMonitoredProperty_NewValue_CallsCallback() 28 | { 29 | _target.AddListener("Name", _listener, (me, sender, args) => me.OnPropertyChanged(sender, args)); 30 | _person.Name = "Foooo"; 31 | 32 | Assert.AreEqual(1, _listener.CallCount); 33 | } 34 | 35 | [Test] 36 | public void AddListenerAndChangeUnmonitoredProperty_NewValue_DoesNotCallCallback() 37 | { 38 | _target.AddListener("Name", _listener, (me, sender, args) => me.OnPropertyChanged(sender, args)); 39 | _person.Age = 1123124; 40 | 41 | Assert.AreEqual(0, _listener.CallCount); 42 | } 43 | 44 | [Test] 45 | public void RemoveListenerAndChangedProperty_NewValue_DoesNotCallCallback() 46 | { 47 | _target.AddListener("Name", _listener, (me, sender, args) => me.OnPropertyChanged(sender, args)); 48 | _target.RemoveListener(_listener, "Name", null); 49 | _person.Name = "Foooo"; 50 | 51 | Assert.AreEqual(0, _listener.CallCount); 52 | } 53 | 54 | [Test] 55 | public void AddListenerAndCollect_NoListenerReferences_ListenerCollected() 56 | { 57 | WeakReference listenerRef = new WeakReference(_listener); 58 | _target.AddListener("Name", _listener, (me, sender, args) => me.OnPropertyChanged(sender, args)); 59 | _listener = null; 60 | GC.Collect(); 61 | Assert.IsFalse(listenerRef.IsAlive); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ClosureToStaticExpressionFactoryTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.Expressions; 7 | 8 | namespace ContinuousLinq.UnitTests 9 | { 10 | [TestFixture] 11 | public class ClosureToStaticExpressionFactoryTest 12 | { 13 | [Test] 14 | public void CreateMetaClosure_OneClosureArgument_WrapsFunctionAndEvaluatesToCorrectResult() 15 | { 16 | Func multiplierByClosureConstant = (x, y, z) => x * (y + z); 17 | 18 | List constants = new List() { 2 }; 19 | Func partialFunction = ClosedToOpenExpressionFactory.CreateMetaClosure>( 20 | multiplierByClosureConstant, 21 | constants); 22 | 23 | int result = partialFunction(3, 5); 24 | Assert.AreEqual(16, result); 25 | } 26 | 27 | [Test] 28 | [Ignore("Performance metrics")] 29 | public void ComparePerformanceOfExpressionCompileVersusCreateMetaClosure() 30 | { 31 | int xx = 2; 32 | System.Linq.Expressions.Expression> multiplierByClosureConstantExpression = (y, z) => xx * (y + z); 33 | DateTime start; 34 | TimeSpan duration; 35 | 36 | start = DateTime.Now; 37 | for (int i = 0; i < 100000; i++) 38 | { 39 | multiplierByClosureConstantExpression.Compile(); 40 | } 41 | duration = DateTime.Now - start; 42 | Console.WriteLine(duration); 43 | 44 | Func multiplierByClosureConstant = (x, y, z) => x * (y + z); 45 | 46 | start = DateTime.Now; 47 | for (int i = 0; i < 100000; i++) 48 | { 49 | List constants = new List() { 2 }; 50 | Func curriedFunction = ClosedToOpenExpressionFactory.CreateMetaClosure>( 51 | multiplierByClosureConstant, 52 | constants); 53 | } 54 | 55 | duration = DateTime.Now - start; 56 | Console.WriteLine(duration); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/SubscriptionTreeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | 7 | namespace ContinuousLinq.UnitTests 8 | { 9 | [TestFixture] 10 | public class SubscriptionTreeTest 11 | { 12 | private SubscriptionTree _target; 13 | private Person _person; 14 | 15 | private PropertyAccessNode _ageAccessNode; 16 | 17 | private PropertyAccessNode _brotherAccessNode; 18 | private SubscriptionNode _brotherNode; 19 | 20 | private ParameterNode _parameterAccessNode; 21 | private SubscriptionNode _parameterNode; 22 | 23 | [SetUp] 24 | public void Setup() 25 | { 26 | _person = new Person(); 27 | 28 | _ageAccessNode = new PropertyAccessNode(typeof(Person).GetProperty("Age")); 29 | _brotherAccessNode = new PropertyAccessNode(typeof(Person).GetProperty("Brother")) { Children = new List() { _ageAccessNode } }; 30 | _parameterAccessNode = new ParameterNode(typeof(Person), "person") { Children = new List() { _brotherAccessNode } }; 31 | 32 | _brotherNode = new SubscriptionNode() { AccessNode = _brotherAccessNode }; 33 | _parameterNode = new SubscriptionNode() { AccessNode = _parameterAccessNode, Children = new List() { _brotherNode } }; 34 | _parameterNode.Subject = _person; 35 | 36 | List nodes = new List() { _parameterNode }; 37 | 38 | _target = new SubscriptionTree(_person, nodes); 39 | } 40 | 41 | [Test] 42 | public void Construct_ChangeFirstLevel_AllNodesSubscribed() 43 | { 44 | int callCount = 0; 45 | _target.PropertyChanged += (sender) => callCount++; 46 | 47 | _person.Brother = new Person(); 48 | 49 | Assert.AreEqual(1, callCount); 50 | } 51 | 52 | [Test] 53 | public void Construct_TwoLevelPropertyTree_AllNodesSubscribed() 54 | { 55 | _person.Brother = new Person(); 56 | 57 | int callCount = 0; 58 | _target.PropertyChanged += (sender) => callCount++; 59 | 60 | _person.Brother.Age = 11; 61 | 62 | Assert.AreEqual(1, callCount); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /OrderBookDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("OrderBookDemo")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("OrderBookDemo")] 15 | [assembly: AssemblyCopyright("Copyright © 2008")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /ContinuousLinq/EventExtensions.tt: -------------------------------------------------------------------------------- 1 | <#@ template language="C#v3.5"#> 2 | 3 | // 4 | // This code was generated by a tool. Any changes made manually will be lost 5 | // the next time this code is regenerated. 6 | // 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.Specialized; 11 | using System.Linq; 12 | using System.Text; 13 | using System.ComponentModel; 14 | 15 | namespace System { 16 | 17 | [System.Diagnostics.DebuggerStepThrough] 18 | public static class EventExtensions { 19 | public static void Raise(this EventHandler handler, object sender, EventArgs args) { 20 | if (handler != null) 21 | handler(sender, args); 22 | } 23 | 24 | public static void Raise(this EventHandler handler, object sender, T args) where T : EventArgs { 25 | if (handler != null) 26 | handler(sender, args); 27 | } 28 | 29 | public static void Raise(this PropertyChangingEventHandler handler, object sender, PropertyChangingEventArgs e) { 30 | if (handler != null) 31 | handler(sender, e); 32 | } 33 | 34 | public static void Raise(this PropertyChangedEventHandler handler, object sender, PropertyChangedEventArgs e) { 35 | if (handler != null) 36 | handler(sender, e); 37 | } 38 | 39 | public static void Raise(this NotifyCollectionChangedEventHandler handler, object sender, NotifyCollectionChangedEventArgs e) { 40 | if (handler != null) 41 | handler(sender, e); 42 | } 43 | 44 | public static void Raise(this Action handler) { 45 | if (handler != null) 46 | handler(); 47 | } 48 | <#for(int i=1;i<=20;i++){#> 49 | public static void Raise<<#FormatRange("T{0}", "," , 1, i); #>>(this Action<<#FormatRange("T{0}", "," , 1, i); #>> handler, <#FormatRange("T{0} t{0}", ", ", 1, i);#>) { 50 | if (handler != null) 51 | handler(<#FormatRange("t{0}", ", ", 1, i);#>); 52 | } 53 | <#}#> 54 | } 55 | } 56 | 57 | <#+ 58 | private void FormatRange(string itemFormatString, string separatorFormatString, int start, int end) 59 | { 60 | for(int i = start; i <= end; i++) 61 | { 62 | this.Write(string.Format(itemFormatString, i)); 63 | if(i != end) 64 | { 65 | this.Write(string.Format(separatorFormatString, i)); 66 | } 67 | } 68 | } 69 | #> -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/CompiledExpressionCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | 7 | namespace ContinuousLinq.Expressions 8 | { 9 | public static class CompiledExpressionCache 10 | { 11 | internal static Dictionary _cache = new Dictionary(); 12 | 13 | public static T CachedCompile(this Expression expression) 14 | where T : class 15 | { 16 | var closureTransformer = new ClosedToOpenExpressionTransformer(expression); 17 | 18 | CompiledExpressionCacheEntry entry = new CompiledExpressionCacheEntry(closureTransformer.OpenVersion); 19 | 20 | Delegate compiledExpression; 21 | if (!_cache.TryGetValue(entry, out compiledExpression)) 22 | { 23 | compiledExpression = closureTransformer.OpenVersion.Compile() as Delegate; 24 | _cache[entry] = compiledExpression; 25 | } 26 | 27 | if (!closureTransformer.WasAlreadyOpen) 28 | { 29 | return ClosedToOpenExpressionFactory.CreateMetaClosure(compiledExpression, closureTransformer.Constants); 30 | } 31 | else 32 | { 33 | return compiledExpression as T; 34 | } 35 | } 36 | } 37 | 38 | internal class CompiledExpressionCacheEntry 39 | { 40 | static ExpressionEqualityComparer _expressionEqualityComparer = new ExpressionEqualityComparer(); 41 | 42 | public LambdaExpression Expression { get; set; } 43 | 44 | public int HashCode { get; set; } 45 | 46 | public CompiledExpressionCacheEntry(LambdaExpression expression) 47 | { 48 | this.Expression = expression; 49 | this.HashCode = _expressionEqualityComparer.GetHashCode(expression); 50 | } 51 | 52 | public override int GetHashCode() 53 | { 54 | return this.HashCode; 55 | } 56 | 57 | public override bool Equals(object obj) 58 | { 59 | if (object.ReferenceEquals(this, obj)) 60 | return true; 61 | 62 | CompiledExpressionCacheEntry objAsEntry = obj as CompiledExpressionCacheEntry; 63 | 64 | return objAsEntry != null && _expressionEqualityComparer.Equals(this.Expression, objAsEntry.Expression); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /OrderBookDemo/Converters/TickCollectionFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using ContinuousLinq.OrderBookDemo.Models; 6 | using System.Windows; 7 | using System.Windows.Media; 8 | using System.Windows.Data; 9 | 10 | namespace ContinuousLinq.OrderBookDemo.Converters 11 | { 12 | public class TickCollectionToPointCollectionConverter : IValueConverter 13 | { 14 | #region IValueConverter Members 15 | private const double PreviousClosingPrice = 100.0; 16 | private static double _fiveMinuteWindow; 17 | 18 | static TickCollectionToPointCollectionConverter() 19 | { 20 | _fiveMinuteWindow = TimeSpan.FromMinutes(5).Ticks; 21 | } 22 | 23 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 24 | { 25 | 26 | double ActualWidth = 400; 27 | double ActualHeight = 160; 28 | 29 | 30 | ReadOnlyContinuousCollection tickCollection = 31 | (ReadOnlyContinuousCollection)value; 32 | 33 | if (tickCollection.Count == 0) 34 | return null; 35 | 36 | double priceMin = Math.Min(PreviousClosingPrice, tickCollection.Min(t => t.Price)); 37 | double priceMax = Math.Max(PreviousClosingPrice, tickCollection.Max(t => t.Price)); 38 | 39 | double tickMin = tickCollection.Min(t => t.TimeStamp.Ticks); 40 | double tickMax = tickCollection.Max(t => t.TimeStamp.Ticks); 41 | 42 | double yScale = ActualHeight/(priceMax-priceMin); 43 | double xScale = ActualWidth / Math.Min((tickMax-tickMin), _fiveMinuteWindow); 44 | 45 | StockTransaction[] querySource = tickCollection.ToArray(); // turn CLINQ off 46 | var newPoints = 47 | from tick in querySource 48 | select new Point 49 | { 50 | X = (tick.TimeStamp.Ticks - tickMin) * xScale, 51 | Y = (ActualHeight - (tick.Price - priceMin) * yScale) 52 | }; 53 | 54 | return new PointCollection(newPoints.ToArray()); 55 | } 56 | 57 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 58 | { 59 | throw new NotImplementedException(); 60 | } 61 | 62 | #endregion 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/PropertyAccessNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.ComponentModel; 8 | using System.Windows; 9 | using System.Collections; 10 | using ContinuousLinq.Expressions; 11 | 12 | namespace ContinuousLinq 13 | { 14 | internal class PropertyAccessNode : PropertyAccessTreeNode 15 | { 16 | public PropertyInfo Property { get; private set; } 17 | 18 | public string PropertyName { get { return this.Property.Name; } } 19 | 20 | public override Type Type 21 | { 22 | get { return this.Property.PropertyType; } 23 | } 24 | 25 | private DynamicProperty _dynamicProperty; 26 | private MemberExpression _Expression; 27 | 28 | public PropertyAccessNode(PropertyInfo property) 29 | { 30 | this.Property = property; 31 | } 32 | 33 | public PropertyAccessNode(MemberExpression expression) { 34 | _Expression = expression; 35 | this.Property = (PropertyInfo)expression.Member; 36 | } 37 | 38 | public override bool IsRedundantVersion(PropertyAccessTreeNode other) 39 | { 40 | var otherAsPropertyNode = other as PropertyAccessNode; 41 | if (otherAsPropertyNode == null) 42 | return false; 43 | 44 | return other != this && otherAsPropertyNode.Property == this.Property; 45 | } 46 | 47 | public override SubscriptionNode CreateSubscription(INotifyPropertyChanged parameter) 48 | { 49 | var subscriptionNode = new SubscriptionNode() 50 | { 51 | AccessNode = this, 52 | }; 53 | 54 | SubscribeToChildren(subscriptionNode, parameter); 55 | 56 | return subscriptionNode; 57 | } 58 | 59 | public object GetPropertyValue(object obj) 60 | { 61 | if (_dynamicProperty == null) { 62 | if (_Expression != null) 63 | _dynamicProperty = DynamicProperty.Create(_Expression); 64 | else 65 | _dynamicProperty = DynamicProperty.Create(this.Property); 66 | } 67 | 68 | return _dynamicProperty.GetValue(obj); 69 | } 70 | 71 | public override string ToString() 72 | { 73 | return string.Format("Node: {0}", this.Property.ToString()); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ContinuousLinq/ReferenceCountTracker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Windows; 7 | using System.Collections.Specialized; 8 | using System.Collections; 9 | 10 | namespace ContinuousLinq 11 | { 12 | public class ReferenceCountTracker 13 | { 14 | private Dictionary ReferenceCounts { get; set; } 15 | 16 | public ReferenceCountTracker() 17 | { 18 | this.ReferenceCounts = new Dictionary(); 19 | } 20 | 21 | public ReferenceCountTracker(IEnumerable collection) 22 | { 23 | this.ReferenceCounts = new Dictionary(); 24 | 25 | foreach (TSource item in collection) 26 | { 27 | Add(item); 28 | } 29 | } 30 | 31 | public IEnumerable Items 32 | { 33 | get { return this.ReferenceCounts.Keys; } 34 | } 35 | 36 | public int this[TSource item] 37 | { 38 | get { return this.ReferenceCounts[item]; } 39 | } 40 | 41 | /// 42 | /// Increments the reference count for the item. Returns true when refrence count goes from 0 to 1. 43 | /// 44 | public bool Add(TSource item) 45 | { 46 | int currentCount; 47 | if (!this.ReferenceCounts.TryGetValue(item, out currentCount)) 48 | { 49 | this.ReferenceCounts.Add(item, 1); 50 | return true; 51 | } 52 | 53 | this.ReferenceCounts[item] = currentCount + 1; 54 | return false; 55 | } 56 | 57 | public void Clear() 58 | { 59 | this.ReferenceCounts.Clear(); 60 | } 61 | 62 | /// 63 | /// Decrements the reference count for the item. Returns true when refrence count goes from 1 to 0. 64 | /// 65 | public bool Remove(TSource item) 66 | { 67 | int currentCount = this.ReferenceCounts[item]; 68 | 69 | if (currentCount == 1) 70 | { 71 | this.ReferenceCounts.Remove(item); 72 | return true; 73 | } 74 | 75 | this.ReferenceCounts[item] = currentCount - 1; 76 | return false; 77 | } 78 | 79 | public bool Contains(TSource item) 80 | { 81 | return this.ReferenceCounts.ContainsKey(item); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /SilverlightTest/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Documents; 8 | using System.Windows.Input; 9 | using System.Windows.Media; 10 | using System.Windows.Media.Animation; 11 | using System.Windows.Shapes; 12 | 13 | namespace SilverlightTest 14 | { 15 | public partial class App : Application 16 | { 17 | 18 | public App() 19 | { 20 | this.Startup += this.Application_Startup; 21 | this.Exit += this.Application_Exit; 22 | this.UnhandledException += this.Application_UnhandledException; 23 | 24 | InitializeComponent(); 25 | } 26 | 27 | private void Application_Startup(object sender, StartupEventArgs e) 28 | { 29 | this.RootVisual = new MainPage(); 30 | } 31 | 32 | private void Application_Exit(object sender, EventArgs e) 33 | { 34 | 35 | } 36 | private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) 37 | { 38 | // If the app is running outside of the debugger then report the exception using 39 | // the browser's exception mechanism. On IE this will display it a yellow alert 40 | // icon in the status bar and Firefox will display a script error. 41 | if (!System.Diagnostics.Debugger.IsAttached) 42 | { 43 | 44 | // NOTE: This will allow the application to continue running after an exception has been thrown 45 | // but not handled. 46 | // For production applications this error handling should be replaced with something that will 47 | // report the error to the website and stop the application. 48 | e.Handled = true; 49 | Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); }); 50 | } 51 | } 52 | private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e) 53 | { 54 | try 55 | { 56 | string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; 57 | errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n"); 58 | 59 | System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");"); 60 | } 61 | catch (Exception) 62 | { 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /OrderBookDemo/Models/StockTransaction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | 7 | namespace ContinuousLinq.OrderBookDemo.Models 8 | { 9 | public enum TransactionType 10 | { 11 | Bid, 12 | Ask, 13 | Execution 14 | } 15 | 16 | public class StockTransaction : INotifyPropertyChanged 17 | { 18 | private string _symbol; 19 | private int _quantity; 20 | private double _price; 21 | private TransactionType _txType; 22 | private DateTime _timeStamp; 23 | 24 | private void NotifyChanged(string propName) 25 | { 26 | if (PropertyChanged != null) 27 | PropertyChanged(this, new PropertyChangedEventArgs(propName)); 28 | } 29 | 30 | public DateTime TimeStamp 31 | { 32 | get 33 | { 34 | return _timeStamp; 35 | } 36 | set 37 | { 38 | _timeStamp = value; 39 | NotifyChanged("TimeStamp"); 40 | } 41 | } 42 | 43 | public string Symbol 44 | { 45 | get 46 | { 47 | return _symbol; 48 | } 49 | set 50 | { 51 | _symbol = value; 52 | NotifyChanged("Symbol"); 53 | } 54 | } 55 | 56 | public int Quantity 57 | { 58 | get 59 | { 60 | return _quantity; 61 | } 62 | set 63 | { 64 | _quantity = value; 65 | NotifyChanged("Quantity"); 66 | } 67 | } 68 | 69 | public double Price 70 | { 71 | get 72 | { 73 | return _price; 74 | } 75 | set 76 | { 77 | _price = value; 78 | NotifyChanged("Price"); 79 | } 80 | } 81 | 82 | public TransactionType TransactionType 83 | { 84 | get 85 | { 86 | return _txType; 87 | } 88 | set 89 | { 90 | _txType = value; 91 | NotifyChanged("TransactionType"); 92 | } 93 | } 94 | 95 | 96 | #region INotifyPropertyChanged Members 97 | 98 | public event PropertyChangedEventHandler PropertyChanged; 99 | 100 | #endregion 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/ClosureToStaticExpressionFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Collections.ObjectModel; 7 | using System.Reflection; 8 | 9 | namespace ContinuousLinq.Expressions 10 | { 11 | public static class ClosedToOpenExpressionFactory 12 | { 13 | private static Dictionary> _partialMethodLookupTable; 14 | 15 | static ClosedToOpenExpressionFactory() 16 | { 17 | _partialMethodLookupTable = new Dictionary>(); 18 | 19 | var allCurryMethods = typeof(Partials).GetMethods(); 20 | 21 | foreach (var method in allCurryMethods) 22 | { 23 | var parameters = method.GetParameters(); 24 | if (!method.IsGenericMethod) 25 | continue; 26 | 27 | var parameterGenericTypeDefinition = parameters[0].ParameterType.GetGenericTypeDefinition(); 28 | 29 | Dictionary matchingMethods; 30 | if (!_partialMethodLookupTable.TryGetValue(parameterGenericTypeDefinition, out matchingMethods)) 31 | { 32 | matchingMethods = new Dictionary(); 33 | _partialMethodLookupTable.Add(parameterGenericTypeDefinition, matchingMethods); 34 | } 35 | matchingMethods.Add(parameters.Length, method); 36 | } 37 | } 38 | 39 | public static T CreateMetaClosure( 40 | Delegate compiledOpenExpression, 41 | List constants) 42 | { 43 | Type compiledOpenExpressionType = compiledOpenExpression.GetType(); 44 | Type compiledOpenExpressionGenericTypeDefinition = compiledOpenExpressionType.GetGenericTypeDefinition(); 45 | 46 | MethodInfo appropriatePartialMethod = _partialMethodLookupTable[compiledOpenExpressionGenericTypeDefinition][constants.Count + 1]; 47 | MethodInfo generatedPartialMethod = appropriatePartialMethod.MakeGenericMethod(compiledOpenExpressionType.GetGenericArguments()); 48 | 49 | object[] arguments = ConstructArgumentsForCallToPartial(compiledOpenExpression, constants); 50 | object partialMethod = generatedPartialMethod.Invoke(null, arguments); 51 | 52 | return (T)partialMethod; 53 | } 54 | 55 | private static object[] ConstructArgumentsForCallToPartial(Delegate compiledOpenExpression, List constants) 56 | { 57 | object[] arguments = new object[constants.Count + 1]; 58 | arguments[0] = compiledOpenExpression; 59 | for (int i = 0; i < constants.Count; i++) 60 | { 61 | arguments[i + 1] = constants[i]; 62 | } 63 | return arguments; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/PausedAggregationTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using NUnit.Framework; 5 | using ContinuousLinq.Aggregates; 6 | using System.Collections.ObjectModel; 7 | 8 | namespace ContinuousLinq.UnitTests 9 | { 10 | [TestFixture] 11 | public class PausedAggregationTest 12 | { 13 | private ObservableCollection _source; 14 | 15 | [SetUp] 16 | public void Setup() 17 | { 18 | _source = ClinqTestFactory.CreateTwoPersonSource(); 19 | } 20 | 21 | [Test] 22 | [Ignore("Need to remove after effects as they do not work")] 23 | public void PauseAggregation_OneItemAddedToCollection_ValueUpdatedAfterUsingBlockExits() 24 | { 25 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 26 | 27 | Assert.AreEqual(30, sum.CurrentValue); 28 | 29 | int callCount = 0; 30 | sum.PropertyChanged += (sender, args) => callCount++; 31 | 32 | using (PausedAggregation pausedAggregation = new PausedAggregation()) 33 | { 34 | _source.Add(new Person() { Age = 30 }); 35 | Assert.AreEqual(0, callCount); 36 | } 37 | Assert.AreEqual(1, callCount); 38 | } 39 | 40 | [Test] 41 | [Ignore("Need to remove after effects as they do not work")] 42 | public void PauseAggregation_PropertyChangedInCollection_ValueUpdatedAfterUsingBlockExits() 43 | { 44 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 45 | 46 | Assert.AreEqual(30, sum.CurrentValue); 47 | 48 | int callCount = 0; 49 | sum.PropertyChanged += (sender, args) => callCount++; 50 | 51 | using (PausedAggregation pausedAggregation = new PausedAggregation()) 52 | { 53 | _source[0].Age = 1000; 54 | Assert.AreEqual(0, callCount); 55 | } 56 | 57 | Assert.AreEqual(1, callCount); 58 | } 59 | 60 | [Test] 61 | [Ignore("This is no longer pertinant after online calculations")] 62 | public void PauseAggregation_NestedPauses_ValueUpdatedAfterUsingBlockExits() 63 | { 64 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 65 | 66 | Assert.AreEqual(30, sum.CurrentValue); 67 | 68 | int callCount = 0; 69 | sum.PropertyChanged += (sender, args) => callCount++; 70 | 71 | using (PausedAggregation pausedAggregation = new PausedAggregation()) 72 | { 73 | using (PausedAggregation pausedAggregationTwo = new PausedAggregation()) 74 | { 75 | _source[0].Age = 1000; 76 | Assert.AreEqual(0, callCount); 77 | } 78 | } 79 | 80 | Assert.AreEqual(1, callCount); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /OrderBookDemo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:2.0.50727.3053 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ContinuousLinq.OrderBookDemo.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ContinuousLinq.OrderBookDemo.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SilverlightTest.Web/SilverlightTestTestPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SilverlightTest 6 | 20 | 21 | 57 | 58 | 59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | Get Microsoft Silverlight 69 | 70 |
71 |
72 | 73 | 74 | -------------------------------------------------------------------------------- /SilverlightTest.Web/SilverlightTestTestPage.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" %> 2 | 3 | 4 | 5 | 6 | SilverlightTest 7 | 21 | 22 | 58 | 59 | 60 |
61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Get Microsoft Silverlight 70 | 71 |
72 |
73 | 74 | 75 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ClinqTestFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.ObjectModel; 6 | 7 | namespace ContinuousLinq.UnitTests 8 | { 9 | public static class ClinqTestFactory 10 | { 11 | public static ObservableCollection CreateTwoPersonSource() 12 | { 13 | return new ObservableCollection() 14 | { 15 | new Person("Bob", 10), 16 | new Person("Jim", 20), 17 | }; 18 | } 19 | 20 | public static ObservableCollection CreateTwoPersonSourceWithParents() 21 | { 22 | var source = CreateTwoPersonSource(); 23 | InitializeParents(source[0]); 24 | InitializeParents(source[1]); 25 | 26 | return source; 27 | } 28 | 29 | public static void InitializeParents(Person person) 30 | { 31 | person.Parents = CreateParents(person); 32 | } 33 | 34 | public static ObservableCollection CreateParents(Person person) 35 | { 36 | return new ObservableCollection() 37 | { 38 | new Person(person.Name + "Parent0", 40), 39 | new Person(person.Name + "Parent1", 41), 40 | }; 41 | } 42 | public static ObservableCollection CreateSixPersonSource() 43 | { 44 | return CreateAnyPersonSource(6); 45 | } 46 | public static ObservableCollectionCreateAnyPersonSource(int persons) 47 | { 48 | ObservableCollection source = new ObservableCollection(); 49 | for (int i = 0; i < persons; i++) 50 | { 51 | source.Add(new Person(i.ToString(), i * 10)); 52 | } 53 | return source; 54 | } 55 | public static ObservableCollection CreateSixPersonSourceWithDuplicates() 56 | { 57 | Person bob = new Person("Bob", 10); 58 | Person jim = new Person("Jim", 20); 59 | 60 | ObservableCollection source = CreateSixPersonSource(); 61 | source[0] = bob; 62 | source[1] = bob; 63 | source[2] = bob; 64 | 65 | source[4] = jim; 66 | source[5] = jim; 67 | 68 | return source; 69 | } 70 | 71 | internal static ObservableCollection CreateGroupablePersonSource() 72 | { 73 | ObservableCollection col = new ObservableCollection(); 74 | // add person objects to collection sufficient to create 10 groups of 6 75 | // based on their age. 76 | for (int x = 0; x < 10; x++) 77 | { 78 | for (int y = 0; y < 6; y++) 79 | { 80 | Person p = new Person() 81 | { 82 | Age = x * 20 + 5, 83 | Name = "Person " + x.ToString() + " " + y.ToString() 84 | }; 85 | col.Add(p); 86 | } 87 | } 88 | 89 | return col; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/FirstOrDefaultTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using ContinuousLinq.Aggregates; 8 | 9 | namespace ContinuousLinq.UnitTests 10 | { 11 | [TestFixture] 12 | public class FirstOrDefaultTest 13 | { 14 | private ObservableCollection _source; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | _source = ClinqTestFactory.CreateTwoPersonSource(); 20 | } 21 | 22 | [Test] 23 | public void FirstOrDefault_Test_GetFirstItem() 24 | { 25 | Person actualFirst = _source[0]; 26 | ContinuousValue firstPerson = _source.ContinuousFirstOrDefault(); 27 | 28 | Assert.AreEqual(actualFirst, firstPerson.CurrentValue); 29 | 30 | } 31 | 32 | [Test] 33 | public void FirstOrDefault_GetFirstItemAfterMove() 34 | { 35 | Person newFirst = new Person() { Age = 40, Name = "New" }; 36 | 37 | ContinuousValue firstPerson = _source.ContinuousFirstOrDefault(); 38 | 39 | _source.Insert(0, newFirst); 40 | 41 | Assert.AreEqual(newFirst, firstPerson.CurrentValue); 42 | 43 | } 44 | 45 | [Test] 46 | public void FirstOrDefault_AfterEffect_Test() 47 | { 48 | int firstPersonsAge = 0; 49 | ContinuousValue firstPerson = _source.ContinuousFirstOrDefault(p => firstPersonsAge = p.Age); 50 | 51 | Assert.AreEqual(_source[0].Age, firstPersonsAge); 52 | Assert.AreEqual(firstPerson.CurrentValue.Age, firstPersonsAge); 53 | } 54 | 55 | [Test] 56 | public void FirstOrDefault_WithPredicate() 57 | { 58 | ContinuousValue firstOverTen = _source.ContinuousFirstOrDefault(p => p.Age > 10); 59 | 60 | Assert.AreEqual(firstOverTen.CurrentValue.Name, "Jim"); 61 | Assert.AreEqual(firstOverTen.CurrentValue.Age, 20); 62 | } 63 | 64 | [Test] 65 | public void FirstOrDefault_Predicate_WithChange() 66 | { 67 | ContinuousValue firstOverThirty = _source.ContinuousFirstOrDefault(p => p.Age > 30); 68 | 69 | Assert.IsNull(firstOverThirty.CurrentValue); 70 | _source[0].Age = 75; 71 | Assert.IsNotNull(firstOverThirty.CurrentValue); 72 | Assert.AreEqual(firstOverThirty.CurrentValue.Age, 75); 73 | } 74 | 75 | [Test] 76 | public void FirstOrDefault_Predicate_AfterEffect() 77 | { 78 | string overThirtyName = null; 79 | ContinuousValue firstOverThirty = _source.ContinuousFirstOrDefault( 80 | p => p.Age > 30, 81 | p => overThirtyName = (p == null) ? "Nobody" : p.Name); 82 | 83 | Assert.IsNull(firstOverThirty.CurrentValue); 84 | Assert.AreEqual(overThirtyName, "Nobody"); 85 | _source[0].Age = 75; 86 | Assert.IsNotNull(firstOverThirty.CurrentValue); 87 | Assert.AreEqual(firstOverThirty.CurrentValue.Name, overThirtyName); 88 | } 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /PerformanceConsole/PerformanceConsole.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {EAA030BB-03AA-4D03-97E9-5B0E85CE796F} 9 | Exe 10 | Properties 11 | PerformanceConsole 12 | PerformanceConsole 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | TRACE;DEBUG;SILVERLIGHT 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | 44 | 3.5 45 | 46 | 47 | 3.5 48 | 49 | 50 | 3.5 51 | 52 | 53 | 54 | 55 | 3.0 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {EFC0FA51-6547-4B90-A84E-905035227972} 67 | ContinuousLinq 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /ContinuousLinq/Collections/ConcatReadOnlyContinuousCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | using System.Linq; 5 | using System.Collections; 6 | 7 | namespace ContinuousLinq.Collections 8 | { 9 | public class ConcatReadOnlyContinuousCollection : ReadOnlyTwoCollectionOperationContinuousCollection 10 | { 11 | public ConcatReadOnlyContinuousCollection(IList first, IList second) 12 | : base(first, second) 13 | { 14 | this.NotifyCollectionChangedMonitorForFirst.Add += OnAddToFirst; 15 | this.NotifyCollectionChangedMonitorForFirst.Remove += OnRemoveFromFirst; 16 | this.NotifyCollectionChangedMonitorForFirst.Reset += OnResetFirst; 17 | this.NotifyCollectionChangedMonitorForFirst.Replace += OnReplaceOnFirst; 18 | 19 | this.NotifyCollectionChangedMonitorForSecond.Add += OnAddToSecond; 20 | this.NotifyCollectionChangedMonitorForSecond.Remove += OnRemoveFromSecond; 21 | this.NotifyCollectionChangedMonitorForSecond.Reset += OnResetSecond; 22 | this.NotifyCollectionChangedMonitorForSecond.Replace += OnReplaceOnSecond; 23 | } 24 | 25 | public override TSource this[int index] 26 | { 27 | get { return index < this.First.Count ? this.First[index] : this.Second[index - this.First.Count]; } 28 | set { throw new AccessViolationException(); } 29 | } 30 | 31 | public override int Count 32 | { 33 | get { return this.First.Count + this.Second.Count; } 34 | } 35 | 36 | #region First Event Handlers 37 | 38 | void OnAddToFirst(object sender, int index, IEnumerable newItems) 39 | { 40 | FireAdd(newItems, index); 41 | } 42 | 43 | void OnRemoveFromFirst(object sender, int index, IEnumerable oldItems) 44 | { 45 | FireRemove(oldItems, index); 46 | } 47 | 48 | void OnResetFirst(object sender) 49 | { 50 | FireReset(); 51 | } 52 | 53 | void OnReplaceOnFirst(object sender, IEnumerable oldItems, int newStartingIndex, IEnumerable newItems) 54 | { 55 | FireReplace(newItems, oldItems, newStartingIndex); 56 | } 57 | 58 | #endregion 59 | 60 | #region Second Event Handlers 61 | 62 | void OnAddToSecond(object sender, int index, IEnumerable newItems) 63 | { 64 | int adjustedIndex = this.First.Count + index; 65 | 66 | FireAdd(newItems, adjustedIndex); 67 | } 68 | 69 | void OnRemoveFromSecond(object sender, int index, IEnumerable oldItems) 70 | { 71 | int adjustedIndex = this.First.Count + index; 72 | 73 | FireRemove(oldItems, adjustedIndex); 74 | } 75 | 76 | void OnResetSecond(object sender) 77 | { 78 | FireReset(); 79 | } 80 | 81 | void OnReplaceOnSecond(object sender, IEnumerable oldItems, int newStartingIndex, IEnumerable newItems) 82 | { 83 | int adjustedIndex = this.First.Count + newStartingIndex; 84 | 85 | FireReplace(newItems, oldItems, adjustedIndex); 86 | } 87 | 88 | #endregion 89 | } 90 | } -------------------------------------------------------------------------------- /SilverlightCompatibility/SilverlightCompatibility.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | AnyCPU 5 | 9.0.30729 6 | 2.0 7 | {1707358D-D349-43F5-B6E3-16600E6A783C} 8 | {A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 9 | Library 10 | Properties 11 | SilverlightCompatibility 12 | SilverlightCompatibility 13 | v3.5 14 | false 15 | true 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | true 28 | full 29 | false 30 | Bin\Debug 31 | DEBUG;TRACE;SILVERLIGHT 32 | true 33 | true 34 | prompt 35 | 4 36 | 37 | 38 | pdbonly 39 | true 40 | Bin\Release 41 | TRACE;SILVERLIGHT 42 | true 43 | true 44 | prompt 45 | 4 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/SkipListTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | 7 | namespace ContinuousLinq.UnitTests 8 | { 9 | [TestFixture] 10 | public class SkipListTest 11 | { 12 | private SkipList _target; 13 | private List _values; 14 | [SetUp] 15 | public void Setup() 16 | { 17 | _values = new List() 18 | { 19 | new object(), 20 | new object(), 21 | new object(), 22 | }; 23 | 24 | _target = new SkipList(); 25 | } 26 | 27 | [Test] 28 | public void Add_OneItem_ItemInList() 29 | { 30 | _target.Add(0, _values[0]); 31 | 32 | var value = _target.GetValue(0); 33 | Assert.AreEqual(_values[0], value); 34 | } 35 | 36 | [Test] 37 | public void Add_TwoItems_ItemsInList() 38 | { 39 | _target.Add(0, _values[0]); 40 | _target.Add(1, _values[1]); 41 | 42 | Assert.AreEqual(_values[0], _target.GetValue(0)); 43 | Assert.AreEqual(_values[1], _target.GetValue(1)); 44 | } 45 | 46 | [Test] 47 | public void Add_ManyManyItems_AllValuesFound() 48 | { 49 | var valueForAll = _values[0]; 50 | int numberOfItems = 10000; 51 | for (int i = 0; i < numberOfItems; i++) 52 | { 53 | _target.Add(i, valueForAll); 54 | } 55 | 56 | for (int i = 0; i < numberOfItems; i++) 57 | { 58 | Assert.AreEqual(valueForAll, _target.GetValue(i)); 59 | } 60 | } 61 | 62 | 63 | [Test] 64 | public void Remove_TwoItems_ItemsNoLongerInList() 65 | { 66 | _target.Add(0, _values[0]); 67 | _target.Add(1, _values[1]); 68 | 69 | _target.Remove(1); 70 | _target.Remove(0); 71 | 72 | object value; 73 | Assert.IsFalse(_target.TryGetValue(0, out value)); 74 | Assert.IsFalse(_target.TryGetValue(1, out value)); 75 | } 76 | 77 | [Test] 78 | public void Remove_ManyManyItems_AllValuesFound() 79 | { 80 | var valueForAll = _values[0]; 81 | int numberOfItems = 10000; 82 | for (int i = 0; i < numberOfItems; i++) 83 | { 84 | _target.Add(i, valueForAll); 85 | } 86 | 87 | for (int i = 0; i < numberOfItems; i++) 88 | { 89 | _target.Remove(i); 90 | } 91 | 92 | for (int i = 0; i < numberOfItems; i++) 93 | { 94 | object value; 95 | Assert.IsFalse(_target.TryGetValue(i, out value)); 96 | } 97 | } 98 | 99 | [Test] 100 | [ExpectedException(typeof(KeyNotFoundException))] 101 | public void GetValue_NoItems_Throws() 102 | { 103 | _target.GetValue(0); 104 | } 105 | 106 | [Test] 107 | [ExpectedException(typeof(KeyNotFoundException))] 108 | public void GetValue_HasItems_Throws() 109 | { 110 | _target.Add(1, 0); 111 | _target.Add(-9, 0); 112 | _target.Add(100, 0); 113 | 114 | _target.GetValue(0); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ContinuousSumTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | //using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.Aggregates; 7 | using System.Collections.ObjectModel; 8 | using System.ComponentModel; 9 | using ContinuousLinq.WeakEvents; 10 | 11 | namespace ContinuousLinq.UnitTests 12 | { 13 | [TestFixture] 14 | public class ContinuousSumTest 15 | { 16 | private ObservableCollection _source; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _source = ClinqTestFactory.CreateTwoPersonSource(); 22 | } 23 | 24 | [Test] 25 | public void SumIntegers_ImmediatelyAfterConstruction_SumCompleted() 26 | { 27 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 28 | 29 | Assert.AreEqual(30, sum.CurrentValue); 30 | } 31 | 32 | [Test] 33 | public void SumIntegers_ChangeValueOfMonitoredPropertyCollection_SumUpdated() 34 | { 35 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 36 | _source[0].Age++; 37 | 38 | Assert.AreEqual(31, sum.CurrentValue); 39 | } 40 | 41 | //[Test] 42 | //public void SumIntegers_ChangeValueOfMonitoredPropertyCollection_PostChangeLambda() 43 | //{ 44 | // int monitoredSum = 0; 45 | 46 | // ContinuousValue sum = _source.ContinuousSum(p => p.Age, newVal => monitoredSum = newVal); 47 | // _source[0].Age += 12; 48 | 49 | // Assert.AreEqual(sum.CurrentValue, 42); 50 | // Assert.AreEqual(monitoredSum, sum.CurrentValue); 51 | //} 52 | 53 | [Test] 54 | public void SumIntegers_ChangeValueOfMonitoredPropertyCollection_PropertyChangedEventFires() 55 | { 56 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 57 | int callCount = 0; 58 | sum.PropertyChanged += (sender, args) => 59 | { 60 | callCount++; 61 | Assert.AreEqual("CurrentValue", args.PropertyName); 62 | }; 63 | 64 | _source[0].Age++; 65 | 66 | Assert.AreEqual(1, callCount); 67 | } 68 | 69 | [Test] 70 | public void SumIntegers_AddItemToCollection_SumUpdated() 71 | { 72 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 73 | _source.Add(new Person() { Age = 10 }); 74 | Assert.AreEqual(40, sum.CurrentValue); 75 | } 76 | 77 | [Test] 78 | public void SumIntegers_RemoveItemFromCollection_SumUpdated() 79 | { 80 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 81 | _source.Remove(_source[0]); 82 | Assert.AreEqual(20, sum.CurrentValue); 83 | } 84 | 85 | [Test] 86 | public void SumIntegers_ReplaceItemInCollection_SumUpdated() 87 | { 88 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 89 | _source[0] = new Person() { Age = 50 }; 90 | Assert.AreEqual(70, sum.CurrentValue); 91 | } 92 | 93 | #if !SILVERLIGHT 94 | [Test] 95 | public void SumIntegers_MoveItemInCollection_SumTheSame() 96 | { 97 | ContinuousValue sum = _source.ContinuousSum(p => p.Age); 98 | _source.Move(0, 1); 99 | 100 | Assert.AreEqual(30, sum.CurrentValue); 101 | } 102 | #endif 103 | 104 | 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/GroupByTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.ComponentModel; 8 | using ContinuousLinq; 9 | using ContinuousLinq.Collections; 10 | 11 | namespace ContinuousLinq.UnitTests 12 | { 13 | [TestFixture] 14 | public class GroupByTest 15 | { 16 | private ObservableCollection _source; 17 | 18 | [SetUp] 19 | public void Setup() 20 | { 21 | _source = ClinqTestFactory.CreateGroupablePersonSource(); 22 | } 23 | 24 | [Test] 25 | public void GroupBy_DotSyntax_CountGroups() 26 | { 27 | GroupingReadOnlyContinuousCollection liveGroup = 28 | _source.GroupBy(p => p.Age); 29 | 30 | Assert.AreEqual(10, liveGroup.Count); 31 | Assert.AreEqual(6, liveGroup[5].Count); 32 | 33 | } 34 | 35 | [Test] 36 | public void GroupBy_CountGroups() 37 | { 38 | GroupingReadOnlyContinuousCollection liveGroup = 39 | from p in _source 40 | group p by p.Age; 41 | 42 | Assert.AreEqual(10, liveGroup.Count); 43 | Assert.AreEqual(6, liveGroup[5].Count); 44 | 45 | } 46 | 47 | [Test] 48 | public void ChangeItemInExistingGroup_NewValueNotMatchingCurrentKey_NewGroupFormed() 49 | { 50 | GroupingReadOnlyContinuousCollection liveGroup = 51 | from p in _source 52 | group p by p.Age; 53 | 54 | _source[0].Age = 999; 55 | 56 | Assert.AreEqual(11, liveGroup.Count); 57 | Assert.AreEqual(1, liveGroup[liveGroup.Count - 1].Count); 58 | } 59 | 60 | [Test] 61 | public void ChangingItem_LastItemInGroup_GroupRemoved() 62 | { 63 | _source = ClinqTestFactory.CreateTwoPersonSource(); 64 | 65 | var group = from p in _source group p by p.Name; 66 | 67 | _source[0].Name = "Foo"; 68 | 69 | Assert.AreEqual(2, group.Count); 70 | } 71 | 72 | [Test] 73 | public void GroupBy_MultipleGroups_UsesAnonymouseTypeForComparison() 74 | { 75 | _source = ClinqTestFactory.CreateTwoPersonSource(); 76 | 77 | var group = from p in _source group p by new { p.Name, p.Age }; 78 | 79 | _source.Add(new Person("Bob", 10)); 80 | _source.Add(new Person("Jim", 20)); 81 | 82 | Assert.AreEqual(2, group.Count); 83 | Assert.AreEqual(2, group[group.Count - 1].Count); 84 | } 85 | 86 | [Test] 87 | public void AddItemToSource_ItemIsADuplicate_AddedToCorrectGroup() 88 | { 89 | _source = ClinqTestFactory.CreateTwoPersonSource(); 90 | 91 | var group = from p in _source group p 92 | by new { p.Name, p.Age }; 93 | 94 | _source.Add(_source[0]); 95 | 96 | Assert.AreEqual(2, group.Count); 97 | Assert.AreEqual(2, group[0].Count); 98 | } 99 | 100 | [Test] 101 | public void RemoveItemFromSource_ItemIsADuplicate_AddedToCorrectGroup() 102 | { 103 | _source = ClinqTestFactory.CreateTwoPersonSource(); 104 | _source.Add(_source[0]); 105 | 106 | var group = from p in _source 107 | group p by new { p.Name, p.Age }; 108 | 109 | _source.Remove(_source[0]); 110 | 111 | Assert.AreEqual(2, group.Count); 112 | Assert.AreEqual(1, group[0].Count); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /ContinuousLinq/Aggregation/StdDev.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace ContinuousLinq.Aggregates 7 | { 8 | internal static class StdDev 9 | { 10 | public static double Compute(Func columnSelector, ICollection dataList) 11 | { 12 | double finalValue = 0; 13 | double variance = 0.0; 14 | 15 | int count = dataList.Count; 16 | double average = dataList.Average(columnSelector); 17 | 18 | if (count == 0) return finalValue; 19 | 20 | foreach (T item in dataList) 21 | { 22 | int columnValue = columnSelector(item); 23 | variance += Math.Pow(columnValue - average, 2); 24 | } 25 | 26 | finalValue = Math.Sqrt(variance / count); 27 | return finalValue; 28 | } 29 | 30 | public static double Compute(Func columnSelector, ICollection dataList) 31 | { 32 | double finalValue = 0; 33 | double variance = 0.0; 34 | 35 | int count = dataList.Count; 36 | double average = dataList.Average(columnSelector); 37 | 38 | if (count == 0) return finalValue; 39 | 40 | foreach (T item in dataList) 41 | { 42 | double columnValue = columnSelector(item); 43 | variance += Math.Pow(columnValue - average, 2); 44 | } 45 | 46 | finalValue = Math.Sqrt(variance / count); 47 | return finalValue; 48 | } 49 | 50 | public static double Compute(Func columnSelector, ICollection dataList) 51 | { 52 | double finalValue = 0; 53 | double variance = 0.0; 54 | 55 | int count = dataList.Count; 56 | double average = dataList.Average(columnSelector); 57 | 58 | if (count == 0) return finalValue; 59 | 60 | foreach (T item in dataList) 61 | { 62 | float columnValue = columnSelector(item); 63 | variance += Math.Pow(columnValue - average, 2); 64 | } 65 | 66 | finalValue = Math.Sqrt(variance / count); 67 | return finalValue; 68 | } 69 | 70 | public static double Compute(Func columnSelector, ICollection dataList) 71 | { 72 | double finalValue = 0; 73 | double variance = 0.0; 74 | 75 | int count = dataList.Count; 76 | double average = dataList.Average(columnSelector); 77 | 78 | if (count == 0) return finalValue; 79 | 80 | foreach (T item in dataList) 81 | { 82 | long columnValue = columnSelector(item); 83 | variance += Math.Pow(columnValue - average, 2); 84 | } 85 | 86 | finalValue = Math.Sqrt(variance / count); 87 | return finalValue; 88 | } 89 | 90 | public static double Compute(Func columnSelector, ICollection dataList) 91 | { 92 | double finalValue = 0; 93 | double variance = 0.0; 94 | 95 | int count = dataList.Count; 96 | double average = (double)dataList.Average(columnSelector); 97 | 98 | if (count == 0) return finalValue; 99 | 100 | foreach (T item in dataList) 101 | { 102 | double columnValue = (double)columnSelector(item); 103 | variance += Math.Pow(columnValue - average, 2); 104 | } 105 | 106 | finalValue = Math.Sqrt(variance / count); 107 | return finalValue; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /ContinuousLinq/WeakEvents/WeakPropertyChangedEventManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Collections.Generic; 4 | 5 | namespace ContinuousLinq.WeakEvents 6 | { 7 | public static class WeakPropertyChangedEventManager 8 | { 9 | internal static WeakDictionary SourceToBridgeTable { get; private set; } 10 | 11 | static WeakPropertyChangedEventManager() 12 | { 13 | SourceToBridgeTable = new WeakDictionary(); 14 | } 15 | 16 | public static void Register( 17 | INotifyPropertyChanged source, 18 | string propertyName, 19 | TListener listener, 20 | Action propertyChangedCallback) 21 | { 22 | WeakPropertyBridge bridge; 23 | bridge = GetBridgeForSource(source); 24 | 25 | bridge.AddListener(propertyName, listener, propertyChangedCallback); 26 | } 27 | 28 | public static void Register( 29 | INotifyPropertyChanged source, 30 | object rootSource, 31 | string propertyName, 32 | TListener listener, 33 | Action propertyChangingCallback, 34 | Action propertyChangedCallback) 35 | { 36 | WeakPropertyBridge bridge; 37 | bridge = GetBridgeForSource(source); 38 | 39 | bridge.AddListener( 40 | propertyName, 41 | listener, 42 | rootSource, 43 | propertyChangingCallback, 44 | propertyChangedCallback); 45 | } 46 | 47 | private static WeakPropertyBridge GetBridgeForSource(INotifyPropertyChanged source) 48 | { 49 | WeakPropertyBridge bridge; 50 | 51 | if (!SourceToBridgeTable.TryGetValue(source, out bridge)) 52 | { 53 | bridge = AddNewPropertyBridgeToTable(source); 54 | } 55 | 56 | //Can happen if the GC does it's magic 57 | if (bridge == null) 58 | { 59 | bridge = AddNewPropertyBridgeToTable(source); 60 | } 61 | return bridge; 62 | } 63 | 64 | private static WeakPropertyBridge AddNewPropertyBridgeToTable( 65 | INotifyPropertyChanged source) 66 | { 67 | WeakPropertyBridge bridge = new WeakPropertyBridge(source); 68 | SourceToBridgeTable[source] = bridge; 69 | return bridge; 70 | } 71 | 72 | private static void OnAllListenersForSourceUnsubscribed(INotifyPropertyChanged source) 73 | { 74 | UnregisterSource(source); 75 | } 76 | 77 | public static void Unregister(INotifyPropertyChanged source, string propertyName, object listener, object rootSubject) 78 | { 79 | WeakPropertyBridge bridge; 80 | 81 | if (!SourceToBridgeTable.TryGetValue(source, out bridge)) 82 | { 83 | return; 84 | } 85 | 86 | if (bridge == null) 87 | { 88 | SourceToBridgeTable.Remove(source); 89 | return; 90 | } 91 | 92 | bridge.RemoveListener(listener, propertyName, rootSubject); 93 | } 94 | 95 | public static void UnregisterSource(INotifyPropertyChanged source) 96 | { 97 | SourceToBridgeTable.Remove(source); 98 | } 99 | 100 | public static void RemoveCollectedEntries() 101 | { 102 | SourceToBridgeTable.RemoveCollectedEntries(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ContinuousMaxTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using NUnit.Framework; 5 | using ContinuousLinq.Aggregates; 6 | using System.Collections.ObjectModel; 7 | using System.ComponentModel; 8 | using ContinuousLinq.WeakEvents; 9 | 10 | namespace ContinuousLinq.UnitTests 11 | { 12 | [TestFixture] 13 | public class ContinuousMaxTest 14 | { 15 | private static ContinuousCollection Items { get; set; } 16 | 17 | private static ContinuousValue MaxValueCV { get; set; } 18 | 19 | private static double Max { get; set; } 20 | 21 | [Test] 22 | [Ignore] 23 | public void Test() 24 | { 25 | // Collection with 1 item to make this test simple 26 | Items = new ContinuousCollection 27 | { 28 | new NotifiableItem { TestValue1 = 3, TestValue2 = 10 }, 29 | }; 30 | 31 | // Start with TestValue1 32 | MaxValueCV = Items.ContinuousMax(item => item.TestValue1, value => Max = value); 33 | Console.WriteLine("MaxValueCV = " + MaxValueCV.CurrentValue); 34 | Console.WriteLine("Max = " + Max); 35 | Console.WriteLine(); 36 | 37 | // Switch to TestValue2 38 | MaxValueCV = Items.ContinuousMax(item => item.TestValue2, value => Max = value); 39 | Console.WriteLine("MaxValueCV = " + MaxValueCV.CurrentValue); 40 | Console.WriteLine("Max = " + Max); 41 | Console.WriteLine(); 42 | GC.Collect(); 43 | WeakPropertyChangedEventManager.RemoveCollectedEntries(); 44 | GC.Collect(); 45 | // Now set TestValue1 46 | Items[0].TestValue1 = 20; 47 | Console.WriteLine("(BUG)"); 48 | Console.WriteLine("MaxValueCV = " + MaxValueCV.CurrentValue); 49 | // BUG: Max is set to 20 when it should be 10 50 | Console.WriteLine("Max = " + Max); 51 | 52 | Assert.AreEqual(10, Max); 53 | 54 | Console.Write("Hit enter to continue..."); 55 | Console.ReadLine(); 56 | } 57 | 58 | 59 | public class NotifiableItem : INotifyPropertyChanged 60 | { 61 | #region Fields 62 | 63 | private double _testValue1; 64 | private double _testValue2; 65 | 66 | #endregion 67 | 68 | #region Properties 69 | 70 | public double TestValue1 71 | { 72 | get { return _testValue1; } 73 | set 74 | { 75 | if (value == _testValue1) 76 | return; 77 | 78 | _testValue1 = value; 79 | OnPropertyChanged("TestValue1"); 80 | } 81 | } 82 | 83 | public double TestValue2 84 | { 85 | get { return _testValue2; } 86 | set 87 | { 88 | if (value == _testValue2) 89 | return; 90 | 91 | _testValue2 = value; 92 | OnPropertyChanged("TestValue2"); 93 | } 94 | } 95 | 96 | #endregion 97 | 98 | #region Members 99 | 100 | public event PropertyChangedEventHandler PropertyChanged; 101 | 102 | private void OnPropertyChanged(string propertyName) 103 | { 104 | if (this.PropertyChanged == null) 105 | return; 106 | 107 | this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 108 | } 109 | 110 | #endregion 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/SelectTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using System.Collections.ObjectModel; 5 | 6 | namespace ContinuousLinq.UnitTests 7 | { 8 | 9 | [TestFixture] 10 | public class SelectTest 11 | { 12 | private ObservableCollection _source; 13 | 14 | [SetUp] 15 | public void Setup() 16 | { 17 | _source = ClinqTestFactory.CreateTwoPersonSource(); 18 | } 19 | 20 | [Test] 21 | public void Select_SimplePassThrough_InputContentsMatchOutputContents() 22 | { 23 | ReadOnlyContinuousCollection output = from person in _source 24 | select person; 25 | 26 | Assert.AreEqual(_source.Count, output.Count); 27 | 28 | for (int i = 0; i < _source.Count; i++) 29 | { 30 | Assert.AreSame(_source[i], output[i]); 31 | } 32 | } 33 | 34 | [Test] 35 | public void Select_ReadOnlyObservableCollection_InputContentsMatchOutputContents() 36 | { 37 | var readOnlySource = new ReadOnlyObservableCollection(_source); 38 | ReadOnlyContinuousCollection output = from person in readOnlySource 39 | select person; 40 | Assert.AreEqual(readOnlySource, output); 41 | } 42 | 43 | [Test] 44 | public void Select_SourceContainsNonNotifyingObject_OnlyMonitorsCollectionChanges() 45 | { 46 | ObservableCollection source = new ObservableCollection { 0, 1, 2, 3 }; 47 | ReadOnlyContinuousCollection result = source.Select(item => item); 48 | int callCount = 0; 49 | result.CollectionChanged += (sender, args) => callCount++; 50 | 51 | source.Add(4); 52 | 53 | Assert.AreEqual(1, callCount); 54 | Assert.AreEqual(4, result[4]); 55 | } 56 | 57 | [Test] 58 | public void DropReference_Always_GarbageCollectsResultCollection() 59 | { 60 | var ageCollection = from person in _source 61 | select person.Age; 62 | 63 | // LINQ execution is deferred. This will execute query. 64 | int count = ageCollection.Count(); 65 | 66 | var weakReference = new WeakReference(ageCollection); 67 | Assert.IsTrue(weakReference.IsAlive); 68 | 69 | ageCollection = null; 70 | GC.Collect(); 71 | Assert.IsFalse(weakReference.IsAlive); 72 | } 73 | 74 | [Test] 75 | public void SelectorCreatesNewObject_Always_ReturnsSameInstance() 76 | { 77 | var personCollection = from person in _source 78 | select new Person(); 79 | 80 | Person personAtZero = personCollection[0]; 81 | Assert.AreSame(personAtZero, personCollection[0]); 82 | } 83 | 84 | [Test] 85 | public void SelectorCreatesNewObjectAndAdds_Always_ReturnsSameInstance() 86 | { 87 | var personCollection = from person in _source 88 | select new Person(); 89 | 90 | var personBeforeAdd = personCollection[0]; 91 | _source.Add(new Person()); 92 | 93 | Assert.AreSame(personBeforeAdd, personCollection[0]); 94 | } 95 | 96 | [Test] 97 | public void LetClause() 98 | { 99 | foreach (var item in _source) 100 | { 101 | item.Brother = new Person(); 102 | } 103 | 104 | var personCollection = from person in _source 105 | select person; 106 | 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /ContinuousLinq/PropertyNotifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Text; 7 | 8 | namespace ContinuousLinq { 9 | public delegate void PropertyChangedEventHandler(T sender, PropertyChangedEventArgs e); 10 | 11 | public class PropertyNotifier where T : INotifyPropertyChanged { 12 | #region Data Members 13 | 14 | private IPropertyAccessTreeSubscriber> _PropertyAccessTree; 15 | private Dictionary _Subscriptions; 16 | public PropertyAccessTree PropertyAccessTree { get; private set; } 17 | 18 | private bool EntireTreeSupportINotifyPropertyChanging { get; set; } 19 | 20 | #endregion 21 | 22 | public event Action, T, PropertyChangedEventArgs> ItemChanged; 23 | public event Action, T, PropertyChangingEventArgs> ItemChanging; 24 | 25 | #region Constructors 26 | 27 | public static PropertyNotifier Create(Expression> expression) { 28 | return new PropertyNotifier(ExpressionPropertyAnalyzer.Analyze(expression)); 29 | } 30 | 31 | public PropertyNotifier(PropertyAccessTree tree) 32 | : base() { 33 | if (tree == null) 34 | throw new ArgumentNullException("tree"); 35 | 36 | PropertyAccessTree = tree; 37 | EntireTreeSupportINotifyPropertyChanging = PropertyAccessTree.DoesEntireTreeSupportINotifyPropertyChanging; 38 | } 39 | #endregion 40 | 41 | #region Methods 42 | 43 | internal void SubscribeToChanges(T subject) { 44 | if (EntireTreeSupportINotifyPropertyChanging) { 45 | if (_PropertyAccessTree == null) { 46 | _PropertyAccessTree = PropertyAccessTree.CreateCallbackSubscription>(OnItemChanging, OnItemChanged); 47 | } 48 | _PropertyAccessTree.SubscribeToChanges(subject, this); 49 | } else { 50 | if (_Subscriptions == null) { 51 | _Subscriptions = new Dictionary(); 52 | } 53 | 54 | SubscriptionTree tree = PropertyAccessTree.CreateSubscriptionTree(subject); 55 | tree.PropertyChanged += OnAnyPropertyChangeInSubscriptionTree; 56 | _Subscriptions.Add(subject, tree); 57 | } 58 | } 59 | 60 | internal void UnsubscribeFromChanges(T subject) { 61 | if (EntireTreeSupportINotifyPropertyChanging) { 62 | if (_PropertyAccessTree == null) 63 | return; 64 | _PropertyAccessTree.UnsubscribeFromChanges(subject, this); 65 | } else { 66 | if (_Subscriptions == null) 67 | return; 68 | 69 | _Subscriptions[subject].PropertyChanged -= OnAnyPropertyChangeInSubscriptionTree; 70 | _Subscriptions.Remove(subject); 71 | } 72 | } 73 | 74 | #endregion 75 | 76 | #region Event Handlers 77 | 78 | private void OnAnyPropertyChangeInSubscriptionTree(SubscriptionTree sender) { 79 | OnItemChanged(this, sender.Parameter, null); 80 | } 81 | 82 | private static void OnItemChanging(PropertyNotifier tree, object itemThatIsChanging, PropertyChangingEventArgs args) { 83 | var itemChanging = tree.ItemChanging; 84 | 85 | if (itemChanging != null) 86 | itemChanging(tree, (T)itemThatIsChanging, args); 87 | } 88 | 89 | private static void OnItemChanged(PropertyNotifier tree, object itemThatChanged, PropertyChangedEventArgs args) { 90 | var itemChanged = tree.ItemChanged; 91 | 92 | if (itemChanged != null) 93 | itemChanged(tree, (T)itemThatChanged, args); 94 | } 95 | 96 | #endregion 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/TestUtilities.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Specialized; 3 | using NUnit.Framework; 4 | 5 | namespace ContinuousLinq.UnitTests 6 | { 7 | public class TestUtilities 8 | { 9 | //public static void AssertCollectionChangedEventArgsEqual(NotifyCollectionChangedEventArgs expectedEventArgs, NotifyCollectionChangedEventArgs actualEventArgs) 10 | //{ 11 | // Assert.AreEqual(expectedEventArgs.Action, actualEventArgs.Action); 12 | 13 | // if (actualEventArgs.NewItems == null) 14 | // Assert.IsNull(expectedEventArgs.NewItems); 15 | // else 16 | // CollectionAssert.AreEquivalent(expectedEventArgs.NewItems, actualEventArgs.NewItems); 17 | 18 | // Assert.AreEqual(expectedEventArgs.NewStartingIndex, actualEventArgs.NewStartingIndex); 19 | 20 | // if (actualEventArgs.OldItems == null) 21 | // Assert.IsNull(expectedEventArgs.OldItems); 22 | // else 23 | // CollectionAssert.AreEquivalent(expectedEventArgs.OldItems, actualEventArgs.OldItems); 24 | 25 | // Assert.AreEqual(expectedEventArgs.OldStartingIndex, actualEventArgs.OldStartingIndex); 26 | //} 27 | 28 | 29 | public static void AssertAdd(NotifyCollectionChangedEventArgs actualEventArgs, int startingIndex, params object[] newItems) 30 | { 31 | Assert.AreEqual(NotifyCollectionChangedAction.Add, actualEventArgs.Action); 32 | 33 | if (actualEventArgs.NewItems == null) 34 | Assert.IsNull(newItems); 35 | else 36 | CollectionAssert.AreEquivalent(newItems, actualEventArgs.NewItems); 37 | 38 | Assert.AreEqual(startingIndex, actualEventArgs.NewStartingIndex); 39 | 40 | Assert.IsNull(actualEventArgs.OldItems); 41 | } 42 | 43 | public static void AssertRemove(NotifyCollectionChangedEventArgs actualEventArgs, int startingIndex, params object[] oldItems) 44 | { 45 | Assert.AreEqual(NotifyCollectionChangedAction.Remove, actualEventArgs.Action); 46 | 47 | Assert.IsNull(actualEventArgs.NewItems); 48 | 49 | CollectionAssert.AreEquivalent(oldItems, actualEventArgs.OldItems); 50 | 51 | Assert.AreEqual(startingIndex, actualEventArgs.OldStartingIndex); 52 | } 53 | 54 | public static void AssertReplace(NotifyCollectionChangedEventArgs actualEventArgs, int startingIndex, object[] newItems, object[] oldItems) 55 | { 56 | Assert.AreEqual(NotifyCollectionChangedAction.Replace, actualEventArgs.Action); 57 | 58 | CollectionAssert.AreEquivalent(newItems, actualEventArgs.NewItems); 59 | 60 | Assert.AreEqual(startingIndex, actualEventArgs.NewStartingIndex); 61 | 62 | CollectionAssert.AreEquivalent(oldItems, actualEventArgs.OldItems); 63 | 64 | #if !SILVERLIGHT 65 | Assert.AreEqual(startingIndex, actualEventArgs.OldStartingIndex); 66 | #endif 67 | } 68 | 69 | public static void AssertReset(NotifyCollectionChangedEventArgs actualEventArgs) 70 | { 71 | Assert.AreEqual(NotifyCollectionChangedAction.Reset, actualEventArgs.Action); 72 | } 73 | 74 | public static List GetCollectionChangedEventArgsList(INotifyCollectionChanged target) 75 | { 76 | var eventArgsList = new List(); 77 | target.CollectionChanged += (sender, e) => eventArgsList.Add(e); 78 | return eventArgsList; 79 | } 80 | } 81 | 82 | public class TestContinuousCollection : ContinuousCollection 83 | { 84 | public TestContinuousCollection() 85 | { 86 | } 87 | 88 | public TestContinuousCollection(List list) 89 | : base(list) 90 | { 91 | } 92 | 93 | public void FireReset() 94 | { 95 | this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/NotifyingPerson.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | 5 | namespace ContinuousLinq.UnitTests 6 | { 7 | [DebuggerDisplay("Name: {Name}, Age: {Age}")] 8 | public class NotifyingPerson : INotifyPropertyChanged, INotifyPropertyChanging 9 | { 10 | private string _name; 11 | private int _age; 12 | private NotifyingPerson _brother; 13 | private ObservableCollection _parents; 14 | 15 | public event PropertyChangedEventHandler PropertyChanged; 16 | public event PropertyChangingEventHandler PropertyChanging; 17 | 18 | public NotifyingPerson() 19 | { 20 | } 21 | 22 | public NotifyingPerson(string name, int age) 23 | { 24 | _name = name; 25 | _age = age; 26 | } 27 | 28 | 29 | public string Name 30 | { 31 | get 32 | { 33 | return _name; 34 | } 35 | set 36 | { 37 | 38 | if (_name == value) 39 | return; 40 | OnPropertyChanging("Name"); 41 | _name = value; 42 | OnPropertyChanged("Name"); 43 | } 44 | } 45 | 46 | public int Age 47 | { 48 | get 49 | { 50 | return _age; 51 | } 52 | set 53 | { 54 | if (_age == value) 55 | return; 56 | OnPropertyChanging("Age"); 57 | _age = value; 58 | OnPropertyChanged("Age"); 59 | } 60 | } 61 | 62 | public NotifyingPerson Brother 63 | { 64 | get { return _brother; } 65 | set 66 | { 67 | if (value == _brother) 68 | return; 69 | OnPropertyChanging("Brother"); 70 | _brother = value; 71 | OnPropertyChanged("Brother"); 72 | } 73 | } 74 | 75 | public ObservableCollection Parents 76 | { 77 | get { return _parents; } 78 | set 79 | { 80 | if (value == _parents) 81 | return; 82 | OnPropertyChanging("Parents"); 83 | _parents = value; 84 | OnPropertyChanged("Parents"); 85 | } 86 | } 87 | 88 | 89 | private void OnPropertyChanged(string property) 90 | { 91 | if (this.PropertyChanged == null) 92 | return; 93 | 94 | this.PropertyChanged(this, new PropertyChangedEventArgs(property)); 95 | } 96 | 97 | private void OnPropertyChanging(string property) 98 | { 99 | if (this.PropertyChanging == null) 100 | return; 101 | 102 | this.PropertyChanging(this, new PropertyChangingEventArgs(property)); 103 | } 104 | 105 | public ReadOnlyContinuousCollection GetPeopleWithSameAge(ObservableCollection people) 106 | { 107 | return from person in people 108 | where person.Age == this.Age 109 | select person; 110 | } 111 | 112 | public ReadOnlyContinuousCollection GetPeopleWithSameAgeAsBrother(ObservableCollection people) 113 | { 114 | return from person in people 115 | where this.Brother != null && person.Age == this.Brother.Age 116 | select person; 117 | } 118 | 119 | public int AddYearsToAge(int amount) 120 | { 121 | this.Age += amount; 122 | return this.Age; ; 123 | } 124 | 125 | public int SubtractYearsFromAge(int amount) 126 | { 127 | this.Age -= amount; 128 | return this.Age; ; 129 | } 130 | 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /ContinuousLinq/Reactive/ReactiveObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.ComponentModel; 6 | using System.Diagnostics; 7 | using System.Windows.Threading; 8 | using System.Xml.Serialization; 9 | 10 | namespace ContinuousLinq.Reactive 11 | { 12 | public interface IReactiveObject : INotifyPropertyChanged, INotifyPropertyChanging 13 | { 14 | } 15 | 16 | public abstract class ReactiveObject : IReactiveObject { 17 | #region Data Members 18 | #if !SILVERLIGHT 19 | [NonSerialized] 20 | #endif 21 | private bool _SuppressPropertyChanged; 22 | 23 | #if !SILVERLIGHT 24 | [NonSerialized] 25 | #endif 26 | private Dispatcher _Dispatcher; 27 | 28 | #endregion 29 | 30 | #region Properties 31 | 32 | private static Dictionary DependsOn { get; set; } 33 | 34 | private List _subscriptionTrees; 35 | 36 | [XmlIgnore] 37 | public bool SuppressPropertyChanged { 38 | get { return _SuppressPropertyChanged; } 39 | set { _SuppressPropertyChanged = value; } 40 | } 41 | 42 | [XmlIgnore] 43 | public Dispatcher Dispatcher { 44 | get { return _Dispatcher; } 45 | set { _Dispatcher = value; } 46 | } 47 | 48 | #endregion 49 | 50 | #region Events & Delegates 51 | 52 | public event PropertyChangedEventHandler PropertyChanged; 53 | 54 | public event PropertyChangingEventHandler PropertyChanging; 55 | 56 | #endregion 57 | 58 | #region Constructors 59 | 60 | static ReactiveObject() 61 | { 62 | DependsOn = new Dictionary(); 63 | } 64 | 65 | protected ReactiveObject() 66 | { 67 | #if !SILVERLIGHT 68 | this.Dispatcher = Dispatcher.CurrentDispatcher; 69 | #endif 70 | Type type = this.GetType(); 71 | 72 | CreateSubscriptionsStartingBaseFirst(type); 73 | } 74 | 75 | #endregion 76 | 77 | #region Methods 78 | 79 | private void CreateSubscriptionsStartingBaseFirst(Type type) 80 | { 81 | if (type == typeof(ReactiveObject)) 82 | return; 83 | 84 | CreateSubscriptionsStartingBaseFirst(type.BaseType); 85 | 86 | IDependsOn dependsOn; 87 | if (DependsOn.TryGetValue(type, out dependsOn)) 88 | { 89 | dependsOn.CreateSubscriptions(this, ref _subscriptionTrees); 90 | } 91 | } 92 | 93 | protected static DependsOn Register() where T : ReactiveObject 94 | { 95 | Type type = typeof(T); 96 | 97 | if (DependsOn.ContainsKey(type)) 98 | throw new InvalidOperationException("Type has already been registered for: " + typeof(T)); 99 | 100 | var dependsOn = new DependsOn(); 101 | 102 | DependsOn[type] = dependsOn; 103 | 104 | return dependsOn; 105 | } 106 | 107 | [DebuggerNonUserCode] 108 | protected internal void OnPropertyChanged(string propertyName) 109 | { 110 | OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 111 | } 112 | 113 | [DebuggerNonUserCode] 114 | protected internal void OnPropertyChanging(string propertyName) 115 | { 116 | OnPropertyChanging(new PropertyChangingEventArgs(propertyName)); 117 | } 118 | 119 | [DebuggerNonUserCode] 120 | protected internal void OnPropertyChanged(PropertyChangedEventArgs args) { 121 | if (this.SuppressPropertyChanged) 122 | return; 123 | 124 | PropertyChanged.Raise(this, args); 125 | } 126 | 127 | [DebuggerNonUserCode] 128 | protected internal void OnPropertyChanging(PropertyChangingEventArgs args) { 129 | if (this.SuppressPropertyChanged) 130 | return; 131 | 132 | PropertyChanging.Raise(this, args); 133 | } 134 | 135 | #endregion 136 | } 137 | } -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/WhereTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.ComponentModel; 8 | using ContinuousLinq; 9 | 10 | namespace ContinuousLinq.UnitTests 11 | { 12 | [TestFixture] 13 | public class WhereTest 14 | { 15 | private ObservableCollection _source; 16 | 17 | [SetUp] 18 | public void Setup() 19 | { 20 | _source = ClinqTestFactory.CreateTwoPersonSource(); 21 | } 22 | 23 | [Test] 24 | public void Where_SimpleOnePropertyFilter_ItemsFiltered() 25 | { 26 | ReadOnlyContinuousCollection output = from person in _source 27 | where person.Age > 10 28 | select person; 29 | 30 | Assert.AreEqual(1, output.Count); 31 | } 32 | 33 | [Test] 34 | public void Where_TwoLevelPropertyFilter_ItemsFiltered() 35 | { 36 | Person brother = new Person(); 37 | brother.Age = 0; 38 | 39 | _source[0].Brother = brother; 40 | 41 | ReadOnlyContinuousCollection output = from person in _source 42 | where person.Brother != null && person.Brother.Age > 10 43 | select person; 44 | 45 | Assert.AreEqual(0, output.Count); 46 | 47 | brother.Age = 100; 48 | 49 | Assert.AreEqual(1, output.Count); 50 | } 51 | 52 | [Test] 53 | public void Where_FilterContainsAConstant_CorrectlyFiltered() 54 | { 55 | Person person = new Person("Ninja", 20); 56 | 57 | ReadOnlyContinuousCollection peopleMatchingAge = person.GetPeopleWithSameAge(_source); 58 | 59 | Assert.AreEqual(1, peopleMatchingAge.Count); 60 | } 61 | 62 | [Test] 63 | public void Where_FilterContainsAConstantWithPropertyChangingOnConstant_CorrectResultsReturned() 64 | { 65 | Person person = new Person("Ninja", 20); 66 | 67 | ReadOnlyContinuousCollection peopleMatchingAge = person.GetPeopleWithSameAge(_source); 68 | 69 | int callCount = 0; 70 | peopleMatchingAge.CollectionChanged += (sender, args) => callCount++; 71 | 72 | person.Age = 10; 73 | 74 | Assert.AreEqual(2, callCount); // one remove and one add 75 | Assert.AreEqual(1, peopleMatchingAge.Count); 76 | } 77 | 78 | [Test] 79 | public void Where_FilterContainsTwoLevelConstantWithConstantNull_CorrectResultsReturned() 80 | { 81 | Person person = new Person("Ninja", 20); 82 | 83 | ReadOnlyContinuousCollection peopleMatchingAge = person.GetPeopleWithSameAgeAsBrother(_source); 84 | 85 | Assert.AreEqual(0, peopleMatchingAge.Count); 86 | } 87 | 88 | 89 | [Test] 90 | public void Where_FilterContainsTwoLevelConstantWithPropertyChangingOnConstant_CorrectResultsReturned() 91 | { 92 | Person person = new Person("Ninja", 100); 93 | 94 | ReadOnlyContinuousCollection peopleMatchingAge = person.GetPeopleWithSameAgeAsBrother(_source); 95 | 96 | person.Brother = new Person("Brother", 20); 97 | 98 | Assert.AreEqual(1, peopleMatchingAge.Count); 99 | } 100 | 101 | [Test] 102 | public void DropReference_Always_GarbageCollectsResultCollection() 103 | { 104 | var ageCollection = from person in _source 105 | where person.Age > 10 106 | select person; 107 | 108 | var weakReference = new WeakReference(ageCollection); 109 | Assert.IsTrue(weakReference.IsAlive); 110 | 111 | ageCollection = null; 112 | GC.Collect(); 113 | Assert.IsFalse(weakReference.IsAlive); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /ContinuousLinq/Expressions/SubscriptionNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | using System.ComponentModel; 8 | using System.Windows; 9 | using System.Collections; 10 | using ContinuousLinq.WeakEvents; 11 | 12 | namespace ContinuousLinq 13 | { 14 | internal class SubscriptionNode 15 | { 16 | private INotifyPropertyChanged _subject; 17 | 18 | internal PropertyAccessTreeNode AccessNode { get; set; } 19 | 20 | internal PropertyAccessNode PropertyAccessNode 21 | { 22 | get { return (PropertyAccessNode)this.AccessNode; } 23 | } 24 | 25 | internal List Children { get; set; } 26 | 27 | public INotifyPropertyChanged Subject 28 | { 29 | get { return _subject; } 30 | set 31 | { 32 | Unsubscribe(); 33 | 34 | _subject = value; 35 | 36 | Subscribe(); 37 | } 38 | } 39 | 40 | public event Action PropertyChanged; 41 | 42 | private void Subscribe() 43 | { 44 | INotifyPropertyChanged subject = this.Subject; 45 | if (subject == null) 46 | return; 47 | 48 | for (int i = 0; i < this.AccessNode.Children.Count; i++) 49 | { 50 | PropertyAccessNode propertyNode = (PropertyAccessNode)this.AccessNode.Children[i]; 51 | 52 | WeakPropertyChangedEventManager.Register( 53 | subject, 54 | propertyNode.Property.Name, 55 | this, 56 | (me, sender, args) => me.OnPropertyChanged(sender, args)); 57 | } 58 | 59 | if (this.Children != null) 60 | { 61 | for (int i = 0; i < this.Children.Count; i++) 62 | { 63 | this.Children[i].UpdateSubject(subject); 64 | } 65 | } 66 | } 67 | 68 | private void UpdateSubject(INotifyPropertyChanged parentSubject) 69 | { 70 | if (parentSubject == null) 71 | this.Subject = null; 72 | 73 | this.Subject = (INotifyPropertyChanged)this.PropertyAccessNode.GetPropertyValue(parentSubject); 74 | } 75 | 76 | private void OnPropertyChanged(object sender, PropertyChangedEventArgs args) 77 | { 78 | if (this.Children != null) 79 | { 80 | SubscriptionNode nodeMatchingPropertyName = null; 81 | for (int i = 0; i < this.Children.Count; i++) 82 | { 83 | var child = this.Children[i]; 84 | if (child.PropertyAccessNode.Property.Name == args.PropertyName) 85 | { 86 | nodeMatchingPropertyName = child; 87 | break; 88 | } 89 | } 90 | 91 | if (nodeMatchingPropertyName == null) 92 | return; 93 | 94 | nodeMatchingPropertyName.UpdateSubject(this.Subject); 95 | } 96 | 97 | if (PropertyChanged == null) 98 | return; 99 | 100 | PropertyChanged(); 101 | } 102 | 103 | private void Unsubscribe() 104 | { 105 | INotifyPropertyChanged subject = this.Subject; 106 | if (subject == null) 107 | return; 108 | 109 | for (int i = 0; i < this.AccessNode.Children.Count; i++) 110 | { 111 | PropertyAccessNode propertyNode = (PropertyAccessNode)this.AccessNode.Children[i]; 112 | 113 | WeakPropertyChangedEventManager.Unregister(subject, propertyNode.Property.Name, this, null); 114 | } 115 | 116 | if (this.Children != null) 117 | { 118 | for (int i = 0; i < this.Children.Count; i++) 119 | { 120 | this.Children[i].Unsubscribe(); 121 | } 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/SelectReadOnlyContinuousCollectionDuplicatesTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using System.Collections.ObjectModel; 7 | using System.Collections.Specialized; 8 | 9 | namespace ContinuousLinq.UnitTests 10 | { 11 | [TestFixture] 12 | public class SelectReadOnlyContinuousCollectionDuplicatesTest 13 | { 14 | private SelectReadOnlyContinuousCollection _target; 15 | private ObservableCollection _source; 16 | 17 | [SetUp] 18 | public void Setup() 19 | { 20 | _source = ClinqTestFactory.CreateSixPersonSourceWithDuplicates(); 21 | _target = new SelectReadOnlyContinuousCollection( 22 | _source, 23 | p => p.Name); 24 | } 25 | 26 | [Test] 27 | public void IndexerGet_ItemsInSource_ItemsMatchSelection() 28 | { 29 | Assert.AreEqual("Bob", _target[0]); 30 | Assert.AreEqual("Bob", _target[1]); 31 | Assert.AreEqual("Bob", _target[2]); 32 | Assert.AreEqual("3", _target[3]); 33 | Assert.AreEqual("Jim", _target[4]); 34 | Assert.AreEqual("Jim", _target[5]); 35 | } 36 | 37 | [Test] 38 | public void ChangeMonitoredPropertyOnItemInSource_Always_FireCollectionChangedEvent() 39 | { 40 | int[] callCounts = new int[3]; 41 | _target.CollectionChanged += (sender, args) => 42 | { 43 | Assert.IsTrue(args.NewStartingIndex >= 0 && args.NewStartingIndex <= 2); 44 | callCounts[args.NewStartingIndex]++; 45 | 46 | Assert.AreEqual(NotifyCollectionChangedAction.Replace, args.Action); 47 | Assert.IsTrue(args.NewItems.Contains("DifferentName")); 48 | Assert.IsTrue(args.OldItems.Contains("Bob")); 49 | }; 50 | 51 | _source[0].Name = "DifferentName"; 52 | Assert.AreEqual(1, callCounts[0]); 53 | Assert.AreEqual(1, callCounts[1]); 54 | Assert.AreEqual(1, callCounts[2]); 55 | } 56 | 57 | [Test] 58 | public void RemoveItemsAndChangeMonitoredPropertyOnItemInSource_Always_FireCollectionChangedEvent() 59 | { 60 | int[] callCounts = new int[2]; 61 | 62 | _source.Remove(_source[0]); 63 | 64 | _target.CollectionChanged += (sender, args) => 65 | { 66 | Assert.IsTrue(args.NewStartingIndex >= 0 && args.NewStartingIndex <= 1); 67 | callCounts[args.NewStartingIndex]++; 68 | 69 | Assert.AreEqual(NotifyCollectionChangedAction.Replace, args.Action); 70 | Assert.IsTrue(args.NewItems.Contains("DifferentName")); 71 | Assert.IsTrue(args.OldItems.Contains("Bob")); 72 | }; 73 | 74 | _source[0].Name = "DifferentName"; 75 | Assert.AreEqual(1, callCounts[0]); 76 | Assert.AreEqual(1, callCounts[1]); 77 | } 78 | 79 | #if !SILVERLIGHT 80 | [Test] 81 | public void MoveItemsAndChangeMonitoredPropertyOnItemInSource_FirstToLast_FireCollectionChangedEvent() 82 | { 83 | _source.Move(0, 5); 84 | 85 | List changedIndices = new List(); 86 | 87 | _target.CollectionChanged += (sender, args) => 88 | { 89 | changedIndices.Add(args.NewStartingIndex); 90 | Assert.AreEqual(args.NewStartingIndex, args.OldStartingIndex); 91 | Assert.AreEqual(NotifyCollectionChangedAction.Replace, args.Action); 92 | Assert.IsTrue(args.NewItems.Contains("DifferentName")); 93 | Assert.IsTrue(args.OldItems.Contains("Bob")); 94 | }; 95 | 96 | _source[5].Name = "DifferentName"; 97 | 98 | Assert.AreEqual(3, changedIndices.Count); 99 | 100 | Assert.IsTrue(changedIndices.Contains(0)); 101 | Assert.IsTrue(changedIndices.Contains(1)); 102 | Assert.IsTrue(changedIndices.Contains(5)); 103 | } 104 | #endif 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/SubscriptionNodeTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | 7 | namespace ContinuousLinq.UnitTests 8 | { 9 | [TestFixture] 10 | public class SubscriptionNodeTest 11 | { 12 | private Person _person; 13 | 14 | private SubscriptionNode _target; 15 | 16 | private PropertyAccessNode _ageAccessNode; 17 | 18 | private PropertyAccessNode _brotherAccessNode; 19 | private SubscriptionNode _brotherNode; 20 | 21 | private ParameterNode _parameterAccessNode; 22 | 23 | [SetUp] 24 | public void Setup() 25 | { 26 | _person = new Person(); 27 | 28 | _ageAccessNode = new PropertyAccessNode(typeof(Person).GetProperty("Age")); 29 | _brotherAccessNode = new PropertyAccessNode(typeof(Person).GetProperty("Brother")) { Children = new List() { _ageAccessNode } }; 30 | _parameterAccessNode = new ParameterNode(typeof(Person), "person") { Children = new List() { _brotherAccessNode } }; 31 | 32 | _brotherNode = new SubscriptionNode() { AccessNode = _brotherAccessNode }; 33 | _target = new SubscriptionNode() { AccessNode = _parameterAccessNode, Children = new List() { _brotherNode } }; 34 | _target.Subject = _person; 35 | } 36 | 37 | [Test] 38 | public void ChangeFirstLevelProperty_TwoLevelPropertyTreeAndPropertyInTree_AllNodesSubscribed() 39 | { 40 | int callCount = 0; 41 | _target.PropertyChanged += () => callCount++; 42 | 43 | Person brother = new Person(); 44 | _person.Brother = brother; 45 | 46 | Assert.AreEqual(1, callCount); 47 | } 48 | 49 | [Test] 50 | public void ChangeSecondLevelProperty_TwoLevelPropertyTreeAndPropertyInTree_AllNodesSubscribed() 51 | { 52 | Person brother = new Person(); 53 | 54 | _person.Brother = brother; 55 | 56 | int parameterNodeCallCount = 0; 57 | _target.PropertyChanged += () => parameterNodeCallCount++; 58 | 59 | int brotherNodeCallCount = 0; 60 | _brotherNode.PropertyChanged += () => brotherNodeCallCount++; 61 | 62 | _person.Brother.Age = 100; 63 | 64 | Assert.AreEqual(0, parameterNodeCallCount); 65 | Assert.AreEqual(1, brotherNodeCallCount); 66 | } 67 | 68 | [Test] 69 | public void ChangeFirstLevelProperty_TwoLevelPropertyTreeAndPropertyNotInTree_EventNotFired() 70 | { 71 | int callCount = 0; 72 | _target.PropertyChanged += () => callCount++; 73 | 74 | Person brother = new Person(); 75 | _person.Age = 12132231; 76 | 77 | Assert.AreEqual(0, callCount); 78 | } 79 | 80 | [Test] 81 | public void ChangeSecondLevelProperty_TwoLevelPropertyTreeAndPropertyNotInTree_EventNotFired() 82 | { 83 | Person brother = new Person(); 84 | 85 | _person.Brother = brother; 86 | 87 | int parameterNodeCallCount = 0; 88 | _target.PropertyChanged += () => parameterNodeCallCount++; 89 | 90 | int brotherNodeCallCount = 0; 91 | _brotherNode.PropertyChanged += () => brotherNodeCallCount++; 92 | 93 | _person.Brother.Name = "adfja"; 94 | 95 | Assert.AreEqual(0, parameterNodeCallCount); 96 | Assert.AreEqual(0, brotherNodeCallCount); 97 | } 98 | 99 | [Test] 100 | public void Unsubscribe_TwoLevelPropertyTree_EventNotFired() 101 | { 102 | Person brother = new Person(); 103 | _person.Brother = brother; 104 | _person.Brother = null; 105 | 106 | int parameterNodeCallCount = 0; 107 | _target.PropertyChanged += () => parameterNodeCallCount++; 108 | 109 | int brotherNodeCallCount = 0; 110 | _brotherNode.PropertyChanged += () => brotherNodeCallCount++; 111 | 112 | brother.Age = 1092213; 113 | 114 | Assert.AreEqual(0, parameterNodeCallCount); 115 | Assert.AreEqual(0, brotherNodeCallCount); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/ClosureToStaticExpressionTransformerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.Expressions; 7 | using System.Linq.Expressions; 8 | 9 | namespace ContinuousLinq.UnitTests 10 | { 11 | [TestFixture] 12 | public class ClosedToOpenExpressionTransformerTest 13 | { 14 | [SetUp] 15 | public void Setup() 16 | { 17 | } 18 | 19 | [Test] 20 | public void Transform_AlreadyOpen_ReturnsOriginalExpression() 21 | { 22 | Expression> original = person => person.Name; 23 | var target = new ClosedToOpenExpressionTransformer(original); 24 | 25 | Assert.AreSame(original, target.OpenVersion); 26 | } 27 | 28 | [Test] 29 | public void WasAlreadyOpen_OriginalOpen_True() 30 | { 31 | Expression> original = person => person.Name; 32 | var target = new ClosedToOpenExpressionTransformer(original); 33 | 34 | Assert.IsTrue(target.WasAlreadyOpen); 35 | } 36 | #if !SILVERLIGHT 37 | [Test] 38 | public void WasAlreadyStatic_OriginalClosed_False() 39 | { 40 | float closedValue = 5.8f; 41 | Expression> original = person => person.Age == closedValue; 42 | var target = new ClosedToOpenExpressionTransformer(original); 43 | 44 | Assert.IsFalse(target.WasAlreadyOpen); 45 | } 46 | #endif 47 | 48 | #if !SILVERLIGHT 49 | [Test] 50 | public void OpenVersion_OriginalHasClosedVariable_OpenVersionHasTransformRootExpression() 51 | { 52 | float closedValue = 5.8f; 53 | Expression> original = person => person.Age == closedValue; 54 | 55 | var target = new ClosedToOpenExpressionTransformer(original); 56 | 57 | Assert.AreEqual(2, target.OpenVersion.Parameters.Count); 58 | 59 | //Can't really test that the static version of the function takes the compiler generated closure... 60 | //Assert.AreEqual(typeof(ContinuousLinq.UnitTests.ClosureToStaticExpressionTransformerTest+<>c__DisplayClass0), target.StaticVersion.Parameters[0].Type); 61 | Assert.AreEqual(typeof(Person), target.OpenVersion.Parameters[1].Type); 62 | Assert.AreEqual(typeof(Func<,,>), target.OpenVersion.Type.GetGenericTypeDefinition()); 63 | } 64 | #endif 65 | [Test] 66 | public void OpenVersion_OriginalIsOpenAndHasConstantDefinedInExpression_DoesNotTransform() 67 | { 68 | Expression> original = person => person.Age == 5.84f; 69 | 70 | var target = new ClosedToOpenExpressionTransformer(original); 71 | 72 | Assert.AreSame(original, target.OpenVersion); 73 | } 74 | 75 | [Test] 76 | [Ignore("Performance metrics")] 77 | public void ComparePerformanceOfExpressionCompileVersusCreateMetaClosure() 78 | { 79 | const int ITERATIONS = 300000; 80 | 81 | int xx = 2; 82 | System.Linq.Expressions.Expression> multiplierByClosureConstantExpression = (y, z) => xx * (y + z); 83 | DateTime start; 84 | TimeSpan duration; 85 | 86 | start = DateTime.Now; 87 | 88 | //for (int i = 0; i < ITERATIONS; i++) 89 | //{ 90 | // multiplierByClosureConstantExpression.Compile(); 91 | //} 92 | 93 | duration = DateTime.Now - start; 94 | 95 | //Console.WriteLine(duration); 96 | 97 | ClosedToOpenExpressionTransformer target = null; 98 | 99 | start = DateTime.Now; 100 | 101 | Type[] types = new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) }; 102 | for (int i = 0; i < ITERATIONS; i++) 103 | { 104 | target = new ClosedToOpenExpressionTransformer(multiplierByClosureConstantExpression); 105 | //Type specificFunctionType = typeof(Func<,,,>).MakeGenericType(types); 106 | } 107 | 108 | duration = DateTime.Now - start; 109 | Console.WriteLine(duration); 110 | Console.WriteLine(target); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ContinuousLinq.UnitTests/WeakEvents/WeakPropertyChangedEventManagerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NUnit.Framework; 6 | using ContinuousLinq.WeakEvents; 7 | using System.ComponentModel; 8 | using System.Threading; 9 | 10 | namespace ContinuousLinq.UnitTests.WeakEvents 11 | { 12 | [TestFixture] 13 | public class WeakPropertyChangedEventManagerTest 14 | { 15 | private ListenerStub _listener; 16 | private WeakReference _listenerReference; 17 | private WeakReference _personReference; 18 | private Person _person; 19 | 20 | [SetUp] 21 | public void Setup() 22 | { 23 | _listener = new ListenerStub(); 24 | _person = new Person(); 25 | 26 | _personReference = new WeakReference(_person); 27 | _listenerReference = new WeakReference(_listener); 28 | } 29 | 30 | [TearDown] 31 | public void TearDown() 32 | { 33 | _person = null; 34 | WeakPropertyChangedEventManager.SourceToBridgeTable.Clear(); 35 | GC.Collect(); 36 | } 37 | 38 | private void RegisterOnPersonName() 39 | { 40 | WeakPropertyChangedEventManager.Register( 41 | _person, 42 | "Name", 43 | _listener, 44 | (me, sender, args) => me.OnPropertyChanged(sender, args)); 45 | } 46 | 47 | [Test] 48 | public void Register_MonitoredPropertyChanges_CallsCallback() 49 | { 50 | RegisterOnPersonName(); 51 | 52 | _person.Name = "Bob"; 53 | 54 | Assert.AreEqual(1, _listener.CallCount); 55 | Assert.AreSame(_person, _listener.Sender); 56 | Assert.IsNotNull(_listener.Args); 57 | Assert.AreEqual("Name", _listener.Args.PropertyName); 58 | } 59 | 60 | [Test] 61 | public void Register_UnmonitoredPropertyChanges_DoesNotCallCallback() 62 | { 63 | RegisterOnPersonName(); 64 | _person.Age = 1; 65 | 66 | Assert.AreEqual(0, _listener.CallCount); 67 | } 68 | 69 | [Test] 70 | public void Register_ListenerReferencesDropped_ListenerGarbageCollected() 71 | { 72 | 73 | RegisterOnPersonName(); 74 | 75 | _listener = null; 76 | GC.Collect(); 77 | Assert.IsFalse(_listenerReference.IsAlive); 78 | } 79 | 80 | [Test] 81 | public void RegisterAndScheduleCleanup_SourceReferencesDropped_SourceGarbageCollected() 82 | { 83 | 84 | RegisterOnPersonName(); 85 | 86 | _person = null; 87 | GC.Collect(); 88 | Assert.IsFalse(_personReference.IsAlive); 89 | } 90 | 91 | [Test] 92 | public void Unregister_MonitoredPropertyChanged_DoesNotFireCallback() 93 | { 94 | RegisterOnPersonName(); 95 | 96 | WeakPropertyChangedEventManager.Unregister(_person, "Name", _listener, null); 97 | _person.Name = "Bob"; 98 | 99 | Assert.AreEqual(0, _listener.CallCount); 100 | } 101 | 102 | [Test] 103 | public void NullOutRefsToSourceAndCollect_Always_SourceCollected() 104 | { 105 | RegisterOnPersonName(); 106 | _person = null; 107 | 108 | GC.Collect(); 109 | 110 | Assert.IsFalse(_personReference.IsAlive); 111 | } 112 | 113 | [Test] 114 | [Ignore("This will fail when everything is run because the test fixtures hold on to references.")] 115 | public void CleanupReferences() 116 | { 117 | RegisterOnPersonName(); 118 | WeakReference personRef = new WeakReference(_person); 119 | _person = null; 120 | 121 | GC.Collect(); 122 | GC.WaitForPendingFinalizers(); 123 | GC.Collect(); 124 | 125 | Assert.IsFalse(personRef.IsAlive); 126 | 127 | WeakPropertyChangedEventManager.RemoveCollectedEntries(); 128 | for (int i = 0; i < 10; i++) 129 | { 130 | GC.Collect(); 131 | GC.WaitForPendingFinalizers(); 132 | GC.Collect(); 133 | WeakPropertyChangedEventManager.RemoveCollectedEntries(); 134 | } 135 | 136 | Assert.AreEqual(0, WeakPropertyChangedEventManager.SourceToBridgeTable.Count); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /ContinuousLinq/WeakEvents/WeakPropertyChangedCallback.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Collections.Generic; 4 | 5 | namespace ContinuousLinq.WeakEvents 6 | { 7 | public interface IWeakCallback 8 | { 9 | WeakReference ListenerReference { get; } 10 | } 11 | 12 | public interface IWeakEventCallback : IWeakCallback 13 | { 14 | bool Invoke(object sender, TArgs args); 15 | WeakReference RootSubject { get; } 16 | } 17 | 18 | public class WeakPropertyChangingCallback : 19 | IWeakEventCallback, 20 | IWeakEventCallback 21 | { 22 | public WeakReference RootSubject { get; set; } 23 | 24 | public WeakReference ListenerReference { get; private set; } 25 | 26 | private Action _propertyChangingCallback; 27 | private Action _propertyChangedCallback; 28 | 29 | public WeakPropertyChangingCallback( 30 | object listener, 31 | object rootSource, 32 | Action propertyChangingCallback, 33 | Action propertyChangedCallback) 34 | { 35 | RootSubject = new WeakReference(rootSource); 36 | ListenerReference = new WeakReference(listener); 37 | _propertyChangingCallback = propertyChangingCallback; 38 | _propertyChangedCallback = propertyChangedCallback; 39 | } 40 | 41 | public bool Invoke(object sender, PropertyChangingEventArgs args) 42 | { 43 | TListener listenerForCallback = (TListener)ListenerReference.Target; 44 | object rootSubject = RootSubject.Target; 45 | if (listenerForCallback != null && rootSubject != null) 46 | { 47 | _propertyChangingCallback(listenerForCallback, sender, rootSubject, args); 48 | return true; 49 | } 50 | return false; 51 | } 52 | 53 | public bool Invoke(object sender, PropertyChangedEventArgs args) 54 | { 55 | TListener listenerForCallback = (TListener)ListenerReference.Target; 56 | object rootSubject = RootSubject.Target; 57 | if (listenerForCallback != null && rootSubject != null) 58 | { 59 | _propertyChangedCallback(listenerForCallback, sender, rootSubject, args); 60 | return true; 61 | } 62 | return false; 63 | } 64 | } 65 | 66 | 67 | public class WeakEventCallback : IWeakEventCallback 68 | { 69 | public WeakReference ListenerReference { get; private set; } 70 | //Unused 71 | public WeakReference RootSubject { get; private set; } 72 | 73 | 74 | private Action _callback; 75 | 76 | public WeakEventCallback( 77 | object listener, 78 | Action callback) 79 | { 80 | this.RootSubject = new WeakReference(null); 81 | ListenerReference = new WeakReference(listener); 82 | _callback = callback; 83 | } 84 | 85 | public bool Invoke(object sender, TArgs args) 86 | { 87 | TListener listenerForCallback = (TListener)ListenerReference.Target; 88 | if (listenerForCallback != null) 89 | { 90 | _callback(listenerForCallback, sender, args); 91 | return true; 92 | } 93 | return false; 94 | } 95 | } 96 | 97 | public interface IWeakEventCallback : IWeakCallback 98 | { 99 | bool Invoke(object sender); 100 | } 101 | 102 | public class WeakEventCallback : IWeakEventCallback 103 | { 104 | public WeakReference ListenerReference { get; private set; } 105 | 106 | private Action _callback; 107 | 108 | public WeakEventCallback( 109 | object listener, 110 | Action callback) 111 | { 112 | ListenerReference = new WeakReference(listener); 113 | _callback = callback; 114 | } 115 | 116 | public bool Invoke(object sender) 117 | { 118 | TListener listenerForCallback = (TListener)ListenerReference.Target; 119 | if (listenerForCallback != null) 120 | { 121 | _callback(listenerForCallback, sender); 122 | return true; 123 | } 124 | 125 | return false; 126 | } 127 | } 128 | } 129 | --------------------------------------------------------------------------------