Commit d1d1894
Changed files (34)
product
infrastructure
container
logging
threading
product/infrastructure/container/DependencyResolutionException.cs
@@ -6,7 +6,7 @@ namespace gorilla.infrastructure.container
public class DependencyResolutionException<T> : Exception
{
public DependencyResolutionException(Exception inner_exception)
- : base("Could not resolve {0}".formatted_using(typeof (T).FullName), inner_exception)
+ : base("Could not resolve {0}".format(typeof (T).FullName), inner_exception)
{
}
}
product/infrastructure/logging/TextLogger.cs
@@ -22,7 +22,7 @@ namespace gorilla.infrastructure.logging
public void debug(string formatted_string, params object[] arguments)
{
writer.WriteLine("[{0}] - {1}", Thread.CurrentThread.ManagedThreadId,
- formatted_string.formatted_using(arguments));
+ formatted_string.format(arguments));
}
public void error(Exception e)
product/infrastructure/threading/AsynchronousCommandProcessor.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using gorilla.infrastructure.logging;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public class AsynchronousCommandProcessor : CommandProcessor
+ {
+ readonly Queue<Command> queued_commands;
+ readonly EventWaitHandle manual_reset;
+ readonly IList<Thread> worker_threads;
+ bool keep_working;
+
+ static public readonly Command Empty = new EmptyCommand();
+
+ public AsynchronousCommandProcessor()
+ {
+ queued_commands = new Queue<Command>();
+ worker_threads = new List<Thread>();
+ manual_reset = new ManualResetEvent(false);
+ }
+
+ public void add(Action command)
+ {
+ add(new AnonymousCommand(command));
+ }
+
+ public void add(Command command_to_process)
+ {
+ lock (queued_commands)
+ {
+ if (queued_commands.Contains(command_to_process)) return;
+ queued_commands.Enqueue(command_to_process);
+ reset_thread();
+ }
+ }
+
+ public void run()
+ {
+ reset_thread();
+ keep_working = true;
+ var worker_thread = new Thread(run_commands);
+ worker_thread.SetApartmentState(ApartmentState.STA);
+ worker_threads.Add(worker_thread);
+ worker_thread.Start();
+ }
+
+ public void stop()
+ {
+ keep_working = false;
+ manual_reset.Set();
+ //manual_reset.Close();
+ }
+
+ [STAThread]
+ void run_commands()
+ {
+ while (keep_working)
+ {
+ manual_reset.WaitOne();
+ run_next_command();
+ }
+ }
+
+ void run_next_command()
+ {
+ var command = Empty;
+ within_lock(() =>
+ {
+ if (queued_commands.Count == 0)
+ manual_reset.Reset();
+ else
+ command = queued_commands.Dequeue();
+ });
+ safely_invoke(() =>
+ {
+ command.run();
+ });
+ reset_thread();
+ }
+
+ void safely_invoke(Action action)
+ {
+ try
+ {
+ action();
+ }
+ catch (Exception e)
+ {
+ this.log().error(e);
+ }
+ }
+
+ void reset_thread()
+ {
+ within_lock(() =>
+ {
+ if (queued_commands.Count > 0) manual_reset.Set();
+ else manual_reset.Reset();
+ });
+ }
+
+ void within_lock(Action action)
+ {
+ lock (queued_commands)
+ {
+ action();
+ }
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/BackgroundThread.cs
@@ -0,0 +1,30 @@
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface IBackgroundThread : DisposableCommand {}
+
+ public class BackgroundThread : IBackgroundThread
+ {
+ readonly IWorkerThread worker_thread;
+
+ public BackgroundThread(DisposableCommand command_to_execute) : this(command_to_execute, new WorkerThread()) {}
+
+ public BackgroundThread(DisposableCommand command_to_execute, IWorkerThread worker_thread)
+ {
+ this.worker_thread = worker_thread;
+ worker_thread.DoWork += (sender, e) => command_to_execute.run();
+ worker_thread.Disposed += (sender, e) => command_to_execute.Dispose();
+ }
+
+ public void run()
+ {
+ worker_thread.begin();
+ }
+
+ public void Dispose()
+ {
+ worker_thread.Dispose();
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/BackgroundThreadFactory.cs
@@ -0,0 +1,49 @@
+using System;
+using gorilla.infrastructure.container;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface IBackgroundThreadFactory
+ {
+ IBackgroundThread create_for<CommandToExecute>() where CommandToExecute : DisposableCommand;
+ IBackgroundThread create_for(Action action);
+ }
+
+ public class BackgroundThreadFactory : IBackgroundThreadFactory
+ {
+ readonly DependencyRegistry registry;
+
+ public BackgroundThreadFactory(DependencyRegistry registry)
+ {
+ this.registry = registry;
+ }
+
+ public IBackgroundThread create_for<CommandToExecute>() where CommandToExecute : DisposableCommand
+ {
+ return new BackgroundThread(registry.get_a<CommandToExecute>());
+ }
+
+ public IBackgroundThread create_for(Action action)
+ {
+ return new BackgroundThread(new AnonymousDisposableCommand(action));
+ }
+
+ class AnonymousDisposableCommand : DisposableCommand
+ {
+ readonly Action action;
+
+ public AnonymousDisposableCommand(Action action)
+ {
+ this.action = action;
+ }
+
+ public void run()
+ {
+ action();
+ }
+
+ public void Dispose() {}
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/CommandProcessor.cs
@@ -0,0 +1,12 @@
+using System;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface CommandProcessor : Command
+ {
+ void add(Action command);
+ void add(Command command_to_process);
+ void stop();
+ }
+}
\ No newline at end of file
product/infrastructure/threading/CurrentThread.cs
@@ -0,0 +1,19 @@
+using System.Threading;
+
+namespace gorilla.infrastructure.threading
+{
+ public class CurrentThread : IThread
+ {
+ public T provide_slot_for<T>() where T : class, new()
+ {
+ var slot = Thread.GetNamedDataSlot(create_key_for<T>());
+ if (null == Thread.GetData(slot)) Thread.SetData(slot, new T());
+ return (T) Thread.GetData(slot);
+ }
+
+ string create_key_for<T>()
+ {
+ return Thread.CurrentThread.ManagedThreadId + GetType().FullName + typeof (T).FullName;
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/IntervalTimer.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Timers;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface ITimer
+ {
+ void start_notifying(ITimerClient client_to_be_notified, TimeSpan span);
+ void stop_notifying(ITimerClient client_to_stop_notifying);
+ }
+
+ public class IntervalTimer : ITimer
+ {
+ readonly ITimerFactory factory;
+ readonly IDictionary<ITimerClient, Timer> timers;
+
+ public IntervalTimer() : this(new TimerFactory())
+ {
+ }
+
+ public IntervalTimer(ITimerFactory factory)
+ {
+ this.factory = factory;
+ timers = new Dictionary<ITimerClient, Timer>();
+ }
+
+ public void start_notifying(ITimerClient client_to_be_notified, TimeSpan span)
+ {
+ stop_notifying(client_to_be_notified);
+
+ var timer = factory.create_for(span);
+ timer.Elapsed += (sender, args) =>
+ {
+ client_to_be_notified.notify();
+ };
+ timer.Start();
+ timers[client_to_be_notified] = timer;
+ }
+
+ public void stop_notifying(ITimerClient client_to_stop_notifying)
+ {
+ if (!timers.ContainsKey(client_to_stop_notifying)) return;
+ timers[client_to_stop_notifying].Stop();
+ timers[client_to_stop_notifying].Dispose();
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/IThread.cs
@@ -0,0 +1,7 @@
+namespace gorilla.infrastructure.threading
+{
+ public interface IThread
+ {
+ T provide_slot_for<T>() where T : class, new();
+ }
+}
\ No newline at end of file
product/infrastructure/threading/ITimerClient.cs
@@ -0,0 +1,7 @@
+namespace gorilla.infrastructure.threading
+{
+ public interface ITimerClient
+ {
+ void notify();
+ }
+}
\ No newline at end of file
product/infrastructure/threading/IWorkerThread.cs
@@ -0,0 +1,12 @@
+using System;
+using System.ComponentModel;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface IWorkerThread : IDisposable
+ {
+ event DoWorkEventHandler DoWork;
+ event EventHandler Disposed;
+ void begin();
+ }
+}
\ No newline at end of file
product/infrastructure/threading/PerThread.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public class PerThread : IContext
+ {
+ readonly IDictionary<int, LocalDataStoreSlot> slots;
+ readonly object mutex = new object();
+
+ public PerThread()
+ {
+ slots = new Dictionary<int, LocalDataStoreSlot>();
+ }
+
+ public bool contains<T>(Key<T> key)
+ {
+ return key.is_found_in(get_items());
+ }
+
+ public void add<T>(Key<T> key, T value)
+ {
+ key.add_value_to(get_items(), value);
+ }
+
+ public T value_for<T>(Key<T> key)
+ {
+ return key.parse_from(get_items());
+ }
+
+ public void remove<T>(Key<T> key)
+ {
+ key.remove_from(get_items());
+ }
+
+ IDictionary get_items()
+ {
+ var id = Thread.CurrentThread.ManagedThreadId;
+ within_lock(() =>
+ {
+ if (!slots.ContainsKey(id))
+ {
+ var slot = Thread.GetNamedDataSlot(GetType().FullName);
+ slots.Add(id, slot);
+ Thread.SetData(slot, new Hashtable());
+ }
+ });
+ return (IDictionary) Thread.GetData(slots[id]);
+ }
+
+ void within_lock(Action action)
+ {
+ lock (mutex) action();
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/PerThreadScopedStorage.cs
@@ -0,0 +1,20 @@
+using System.Collections;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public class PerThreadScopedStorage : IScopedStorage
+ {
+ readonly IThread current_thread;
+
+ public PerThreadScopedStorage(IThread current_thread)
+ {
+ this.current_thread = current_thread;
+ }
+
+ public IDictionary provide_storage()
+ {
+ return current_thread.provide_slot_for<Hashtable>();
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/SynchronizationContextFactory.cs
@@ -0,0 +1,23 @@
+using System.Threading;
+using gorilla.infrastructure.container;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface ISynchronizationContextFactory : Factory<ISynchronizationContext> {}
+
+ public class SynchronizationContextFactory : ISynchronizationContextFactory
+ {
+ readonly DependencyRegistry registry;
+
+ public SynchronizationContextFactory(DependencyRegistry registry)
+ {
+ this.registry = registry;
+ }
+
+ public ISynchronizationContext create()
+ {
+ return new SynchronizedContext(registry.get_a<SynchronizationContext>());
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/SynchronizedCommand.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Threading;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface ISynchronizedCommand : Command<Action>, Command<Command> {}
+
+ public class SynchronizedCommand : ISynchronizedCommand
+ {
+ readonly SynchronizationContext context;
+
+ public SynchronizedCommand(SynchronizationContext context)
+ {
+ this.context = context;
+ }
+
+ public void run(Action item)
+ {
+ context.Post(x => item(), new object());
+ }
+
+ public void run(Command item)
+ {
+ run(item.run);
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/SynchronizedContext.cs
@@ -0,0 +1,23 @@
+using System.Threading;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface ISynchronizationContext : Command<Command> {}
+
+ public class SynchronizedContext : ISynchronizationContext
+ {
+ readonly SynchronizationContext context;
+
+ public SynchronizedContext(SynchronizationContext context)
+ {
+ this.context = context;
+ }
+
+ public void run(Command item)
+ {
+ context.Post(x => item.run(), new object());
+ //context.Send(x => item.run(), new object());
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/SynchronousCommandProcessor.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ public class SynchronousCommandProcessor : CommandProcessor
+ {
+ readonly Queue<Command> queued_commands;
+
+ public SynchronousCommandProcessor()
+ {
+ queued_commands = new Queue<Command>();
+ }
+
+ public void add(Action command)
+ {
+ add(new AnonymousCommand(command));
+ }
+
+ public void add(Command command_to_process)
+ {
+ queued_commands.Enqueue(command_to_process);
+ }
+
+ public void run()
+ {
+ while (queued_commands.Count > 0) queued_commands.Dequeue().run();
+ }
+
+ public void stop()
+ {
+ queued_commands.Clear();
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/ThreadingExtensions.cs
@@ -0,0 +1,12 @@
+using gorilla.utility;
+
+namespace gorilla.infrastructure.threading
+{
+ static public class ThreadingExtensions
+ {
+ static public IBackgroundThread on_a_background_thread(this DisposableCommand command)
+ {
+ return new BackgroundThread(command);
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/TimerFactory.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Timers;
+
+namespace gorilla.infrastructure.threading
+{
+ public interface ITimerFactory
+ {
+ Timer create_for(TimeSpan span);
+ }
+
+ public class TimerFactory : ITimerFactory
+ {
+ public Timer create_for(TimeSpan span)
+ {
+ if (span.Seconds > 0) {
+ var milliseconds = span.Seconds*1000;
+ return new Timer(milliseconds);
+ }
+ return new Timer(span.Ticks);
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/threading/WorkerThread.cs
@@ -0,0 +1,50 @@
+using System;
+using System.ComponentModel;
+using gorilla.infrastructure.logging;
+
+namespace gorilla.infrastructure.threading
+{
+ public class WorkerThread : Component, IWorkerThread
+ {
+ static readonly object do_work_key = new object();
+ bool is_running;
+ readonly Action background_thread;
+
+ public WorkerThread()
+ {
+ background_thread = worker_thread_start;
+ }
+
+ public event DoWorkEventHandler DoWork
+ {
+ add { Events.AddHandler(do_work_key, value); }
+ remove { Events.RemoveHandler(do_work_key, value); }
+ }
+
+ public void begin()
+ {
+ if (is_running)
+ {
+ throw new InvalidOperationException("Worker Thread Is Already Running");
+ }
+ is_running = true;
+ background_thread.BeginInvoke(null, null);
+ }
+
+ void worker_thread_start()
+ {
+ try
+ {
+ var handler = (DoWorkEventHandler) Events[do_work_key];
+ if (handler != null)
+ {
+ handler(this, new DoWorkEventArgs(null));
+ }
+ }
+ catch (Exception e)
+ {
+ this.log().error(e);
+ }
+ }
+ }
+}
\ No newline at end of file
product/infrastructure/infrastructure.csproj
@@ -90,6 +90,26 @@
<Compile Include="reflection\EnvironmentExtensions.cs" />
<Compile Include="reflection\Assembly.cs" />
<Compile Include="registries\DefaultRegistry.cs" />
+ <Compile Include="threading\AsynchronousCommandProcessor.cs" />
+ <Compile Include="threading\BackgroundThread.cs" />
+ <Compile Include="threading\BackgroundThreadFactory.cs" />
+ <Compile Include="threading\CommandProcessor.cs" />
+ <Compile Include="threading\CurrentThread.cs" />
+ <Compile Include="threading\IntervalTimer.cs" />
+ <Compile Include="threading\IThread.cs" />
+ <Compile Include="threading\ITimerClient.cs" />
+ <Compile Include="threading\IWorkerThread.cs" />
+ <Compile Include="threading\PerThread.cs" />
+ <Compile Include="threading\PerThreadScopedStorage.cs" />
+ <Compile Include="threading\SynchronizationContextFactory.cs" />
+ <Compile Include="threading\SynchronizedCommand.cs" />
+ <Compile Include="threading\SynchronizedContext.cs" />
+ <Compile Include="threading\SynchronousCommandProcessor.cs" />
+ <Compile Include="threading\ThreadingExtensions.cs" />
+ <Compile Include="threading\TimerFactory.cs" />
+ <Compile Include="threading\WorkerThread.cs">
+ <SubType>Component</SubType>
+ </Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\utility\utility.csproj">
product/utility/Callback.cs
@@ -4,7 +4,7 @@ namespace gorilla.utility
{
}
- public interface Callback<in T> : ParameterizedCommand<T>
+ public interface Callback<in T> : Command<T>
{
}
}
\ No newline at end of file
product/utility/CallbackCommand.cs
@@ -1,6 +1,6 @@
namespace gorilla.utility
{
- public interface CallbackCommand<out T> : ParameterizedCommand<Callback<T>>
+ public interface CallbackCommand<out T> : Command<Callback<T>>
{
}
}
\ No newline at end of file
product/utility/Command.cs
@@ -4,4 +4,9 @@ namespace gorilla.utility
{
void run();
}
+
+ public interface Command<in T>
+ {
+ void run(T item);
+ }
}
\ No newline at end of file
product/utility/ExpressionExtensions.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace gorilla.utility
+{
+ static public class ExpressionExtensions
+ {
+ static public PropertyInfo pick_property<T>(this Expression<Func<T, object>> expression)
+ {
+ return (PropertyInfo) member_expression(expression).Member;
+ }
+
+ static MemberExpression member_expression<T>(Expression<Func<T, object>> expression)
+ {
+ if (expression.Body.NodeType == ExpressionType.Convert)
+ return ((UnaryExpression) expression.Body).Operand as MemberExpression;
+ if (expression.Body.NodeType == ExpressionType.MemberAccess)
+ return expression.Body as MemberExpression;
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
product/utility/IContext.cs
@@ -0,0 +1,10 @@
+namespace gorilla.utility
+{
+ public interface IContext
+ {
+ bool contains<T>(Key<T> key);
+ void add<T>(Key<T> key, T value);
+ T value_for<T>(Key<T> key);
+ void remove<T>(Key<T> key);
+ }
+}
\ No newline at end of file
product/utility/IScopedStorage.cs
@@ -0,0 +1,9 @@
+using System.Collections;
+
+namespace gorilla.utility
+{
+ public interface IScopedStorage
+ {
+ IDictionary provide_storage();
+ }
+}
\ No newline at end of file
product/utility/Key.cs
@@ -0,0 +1,12 @@
+using System.Collections;
+
+namespace gorilla.utility
+{
+ public interface Key<T>
+ {
+ bool is_found_in(IDictionary items);
+ T parse_from(IDictionary items);
+ void remove_from(IDictionary items);
+ void add_value_to(IDictionary items, T value);
+ }
+}
\ No newline at end of file
product/utility/Mapper.cs
@@ -4,4 +4,9 @@ namespace gorilla.utility
{
Output map_from(Input item);
}
+
+ public interface Mapper
+ {
+ Output map_from<Input, Output>(Input item);
+ }
}
\ No newline at end of file
product/utility/MappingExtensions.cs
@@ -4,31 +4,42 @@ using System.Linq;
namespace gorilla.utility
{
- public static class MappingExtensions
+ static public class MappingExtensions
{
- public static Output map_using<Input, Output>(this Input item, Converter<Input, Output> conversion)
+ static public Output map_using<Input, Output>(this Input item, Converter<Input, Output> conversion)
{
return conversion(item);
}
- public static Output map_using<Input, Output>(this Input item, Mapper<Input, Output> mapper)
+ static public Output map_using<Input, Output>(this Input item, Mapper<Input, Output> mapper)
{
return map_using(item, x => mapper.map_from(x));
}
- public static IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
+ static public Output map_using<Input, Output>(this Input item, Mapper mapper)
+ {
+ return map_using(item, x => mapper.map_from<Input, Output>(x));
+ }
+
+ static public IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
Converter<Input, Output> mapper)
{
- return null == items ? new List<Output>() : items.Select(x => mapper(x));
+ return null == items ? Enumerable.Empty<Output>() : items.Select(x => mapper(x));
}
- public static IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
+ static public IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
Mapper<Input, Output> mapper)
{
return map_all_using(items, x => mapper.map_from(x));
}
- public static Mapper<Left, Right> then<Left, Middle, Right>(this Mapper<Left, Middle> left,
+ static public IEnumerable<Output> map_all_using<Input, Output>(this IEnumerable<Input> items,
+ Mapper mapper)
+ {
+ return map_all_using(items, x => mapper.map_from<Input, Output>(x));
+ }
+
+ static public Mapper<Left, Right> then<Left, Middle, Right>(this Mapper<Left, Middle> left,
Mapper<Middle, Right> right)
{
return new ChainedMapper<Left, Middle, Right>(left, right);
product/utility/ParameterizedCommand.cs
@@ -1,7 +0,0 @@
-namespace gorilla.utility
-{
- public interface ParameterizedCommand<in T>
- {
- void run(T item);
- }
-}
\ No newline at end of file
product/utility/RegistryExtensions.cs
@@ -17,7 +17,7 @@ namespace gorilla.utility
}
catch (Exception exception)
{
- throw new Exception("Could Not Find an implementation of".formatted_using(typeof (K)), exception);
+ throw new Exception("Could Not Find an implementation of".format(typeof (K)), exception);
}
}
product/utility/StringExtensions.cs
@@ -2,7 +2,7 @@ namespace gorilla.utility
{
static public class StringExtensions
{
- static public string formatted_using(this string formatted_string, params object[] arguments)
+ static public string format(this string formatted_string, params object[] arguments)
{
return string.Format(formatted_string, arguments);
}
@@ -19,7 +19,7 @@ namespace gorilla.utility
static public string to_string<T>(this T item)
{
- return "{0}".formatted_using(item);
+ return "{0}".format(item);
}
}
}
\ No newline at end of file
product/utility/utility.csproj
@@ -77,6 +77,7 @@
<Compile Include="EmptyCallback.cs" />
<Compile Include="EmptyCommand.cs" />
<Compile Include="DefaultConstructorFactory.cs" />
+ <Compile Include="ExpressionExtensions.cs" />
<Compile Include="FactoryDelegate.cs" />
<Compile Include="FilteredVisitor.cs" />
<Compile Include="FuncSpecification.cs" />
@@ -86,14 +87,16 @@
<Compile Include="Command.cs" />
<Compile Include="Configuration.cs" />
<Compile Include="ComponentFactory.cs" />
+ <Compile Include="IContext.cs" />
<Compile Include="Id.cs" />
<Compile Include="DisposableCommand.cs" />
<Compile Include="Factory.cs" />
<Compile Include="Identifiable.cs" />
<Compile Include="Import.cs" />
+ <Compile Include="IScopedStorage.cs" />
+ <Compile Include="Key.cs" />
<Compile Include="Mapper.cs" />
<Compile Include="Notification.cs" />
- <Compile Include="ParameterizedCommand.cs" />
<Compile Include="Parser.cs" />
<Compile Include="Query.cs" />
<Compile Include="Registry.cs" />