mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-23 17:34:49 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c607d1254e | ||
|
|
e90914664f | ||
|
|
fc855d407b | ||
|
|
e3a4713b3b | ||
|
|
f85896e947 | ||
|
|
131e2f87f4 | ||
|
|
4a330637a7 | ||
|
|
fa124a0afc | ||
|
|
72fd823643 | ||
|
|
644388edad | ||
|
|
cbb05c8b79 | ||
|
|
066c9f93a7 | ||
|
|
9aa7459b0f | ||
|
|
f8a813c97b | ||
|
|
be6a6de65a | ||
|
|
ffe3e67241 | ||
|
|
141d911eb0 | ||
|
|
d6abf3fdf6 | ||
|
|
46a1ea09b6 | ||
|
|
2dc705d335 | ||
|
|
0700a357dd | ||
|
|
5fb7636ed4 | ||
|
|
196c2a535a | ||
|
|
db50ada952 | ||
|
|
087b04fd62 | ||
|
|
ea73351d39 | ||
|
|
ca1fae29b0 | ||
|
|
1916c2b750 | ||
|
|
3af2544e70 | ||
|
|
20e8aa93f2 | ||
|
|
3937902f38 | ||
|
|
021d5781a3 | ||
|
|
b429e4bc53 | ||
|
|
4a203e2449 | ||
|
|
d41203b856 | ||
|
|
2f21379e52 | ||
|
|
bd2ea606ae | ||
|
|
1f20c07e94 | ||
|
|
1be588b86a | ||
|
|
488df297fc | ||
|
|
80a4d94358 | ||
|
|
6a40f3ce18 | ||
|
|
d564a0a423 | ||
|
|
a9a544c433 | ||
|
|
2e0837f5c8 | ||
|
|
77be0ec477 |
28
CHANGELOG.md
28
CHANGELOG.md
@@ -6,6 +6,34 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [9.2.0] - 2019-03-01
|
||||
### Added
|
||||
- Added Type IsAssignableTo extension shim
|
||||
- Added constructor to BiDictionary to instantiate from an existing dict
|
||||
|
||||
### Changed
|
||||
- Fixed bug preventing deserialization of XML lists
|
||||
- Crestron ConsoleResponse uses PrintLine instead of Print
|
||||
- Use PrintLine instead of ConsoleResponse on Crestron server
|
||||
|
||||
## [9.1.0] - 2019-02-07
|
||||
### Added
|
||||
- Added SubscribeEvent shim for delegate callbacks
|
||||
- Extension method for reading JSON token as a GUID
|
||||
- Added ToStringJsonConverter
|
||||
|
||||
### Changed
|
||||
- Significantly reduced size of JSON serialized Types
|
||||
- Small logging optimizations
|
||||
|
||||
## [9.0.0] - 2019-01-29
|
||||
### Added
|
||||
- IcdConsole.OnConsolePrint event
|
||||
|
||||
### Changed
|
||||
- Better VC-4 support for IcdConsole
|
||||
- JSON refactoring for simpler deserialization
|
||||
|
||||
## [8.3.0] - 2019-01-25
|
||||
### Added
|
||||
- Added SimplSharpProMono to eRuntimeEnvironment enum
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Collections
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class AsyncEventQueueTest
|
||||
{
|
||||
[Test]
|
||||
public void ItemDequeuedFeedbackTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CountTest()
|
||||
{
|
||||
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
|
||||
{
|
||||
queue.OnItemDequeued +=
|
||||
(sender, args) =>
|
||||
{
|
||||
ThreadingUtils.Sleep(200);
|
||||
};
|
||||
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
|
||||
for (int index = 0; index < 5; index++)
|
||||
queue.Enqueue(index);
|
||||
|
||||
Assert.AreEqual(5, queue.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnqueueTest()
|
||||
{
|
||||
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
|
||||
{
|
||||
List<GenericEventArgs<int>> eventArgs = new List<GenericEventArgs<int>>();
|
||||
queue.OnItemDequeued +=
|
||||
(sender, args) =>
|
||||
{
|
||||
eventArgs.Add(args);
|
||||
};
|
||||
|
||||
Assert.AreEqual(0, eventArgs.Count);
|
||||
|
||||
for (int index = 0; index < 5; index++)
|
||||
queue.Enqueue(index);
|
||||
|
||||
ThreadingUtils.Sleep(500);
|
||||
|
||||
Assert.AreEqual(5, eventArgs.Count);
|
||||
|
||||
Assert.AreEqual(0, eventArgs[0].Data);
|
||||
Assert.AreEqual(1, eventArgs[1].Data);
|
||||
Assert.AreEqual(2, eventArgs[2].Data);
|
||||
Assert.AreEqual(3, eventArgs[3].Data);
|
||||
Assert.AreEqual(4, eventArgs[4].Data);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearTest()
|
||||
{
|
||||
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
|
||||
{
|
||||
queue.OnItemDequeued +=
|
||||
(sender, args) =>
|
||||
{
|
||||
ThreadingUtils.Sleep(200);
|
||||
};
|
||||
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
|
||||
for (int index = 0; index < 5; index++)
|
||||
queue.Enqueue(index);
|
||||
|
||||
Assert.AreEqual(5, queue.Count);
|
||||
|
||||
queue.Clear();
|
||||
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using ICD.Common.Utils.IO;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
@@ -17,6 +18,36 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadObjectTest()
|
||||
{
|
||||
const string json =
|
||||
"{\"name\":\"Test\",\"help\":\"Test test.\",\"type\":\"System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\",\"value\":\"Test\"}";
|
||||
|
||||
Dictionary<string, string> expected = new Dictionary<string, string>
|
||||
{
|
||||
{"name", "Test"},
|
||||
{"help", "Test test."},
|
||||
{"type", "System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"},
|
||||
{"value", "Test"}
|
||||
};
|
||||
|
||||
Dictionary<string, string> deserialized = new Dictionary<string, string>();
|
||||
|
||||
using (IcdStringReader textReader = new IcdStringReader(json))
|
||||
{
|
||||
using (JsonReader reader = new JsonTextReader(textReader.WrappedTextReader))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
|
||||
reader.Read();
|
||||
reader.ReadObject(serializer, (p, r, s) => deserialized.Add(p, (string)r.Value));
|
||||
}
|
||||
}
|
||||
|
||||
Assert.IsTrue(deserialized.DictionaryEqual(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValueAsIntTest()
|
||||
{
|
||||
@@ -78,53 +109,5 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
|
||||
Assert.IsTrue(deserialized.SequenceEqual(new[] {1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeDictionaryTest()
|
||||
{
|
||||
Dictionary<int, string> dict = new Dictionary<int, string>
|
||||
{
|
||||
{1, "Item 1"},
|
||||
{10, "Item 2"},
|
||||
{15, "Item 3"}
|
||||
};
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
using (StringWriter stringWriter = new StringWriter(stringBuilder))
|
||||
{
|
||||
using (JsonWriter writer = new JsonTextWriter(stringWriter))
|
||||
{
|
||||
serializer.SerializeDictionary(writer, dict);
|
||||
}
|
||||
}
|
||||
|
||||
string json = stringBuilder.ToString();
|
||||
Assert.AreEqual("{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeDictionaryTest()
|
||||
{
|
||||
const string json = "{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}";
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
Dictionary<int, string> deserialized;
|
||||
|
||||
using (StringReader stringReader = new StringReader(json))
|
||||
{
|
||||
using (JsonReader reader = new JsonTextReader(stringReader))
|
||||
{
|
||||
reader.Read();
|
||||
deserialized = serializer.DeserializeDictionary<int, string>(reader).ToDictionary();
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(3, deserialized.Count);
|
||||
Assert.AreEqual("Item 1", deserialized[1]);
|
||||
Assert.AreEqual("Item 2", deserialized[10]);
|
||||
Assert.AreEqual("Item 3", deserialized[15]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,22 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
Assert.AreEqual(expected, type.GetNameWithoutGenericArity());
|
||||
}
|
||||
|
||||
[TestCase(typeof(int), "System.Int32")]
|
||||
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32]]")]
|
||||
[TestCase(typeof(KeyValuePair<int, string>), "System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]")]
|
||||
[TestCase(typeof(List<>), "System.Collections.Generic.List`1")]
|
||||
public void GetMinimalNameTest(Type type, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, type.GetMinimalName());
|
||||
}
|
||||
|
||||
[TestCase(typeof(int), "System.Int32, System.Private.CoreLib")]
|
||||
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")]
|
||||
public void GetNameWithoutAssemblyDetailsTest(Type type, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, type.GetNameWithoutAssemblyDetails());
|
||||
}
|
||||
|
||||
[TestCase(typeof(string), "string")]
|
||||
[TestCase(typeof(int?), "int?")]
|
||||
[TestCase(typeof(List<int?>), "List<int?>")]
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using ICD.Common.Utils.IO;
|
||||
using ICD.Common.Utils.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Json
|
||||
@@ -141,32 +140,6 @@ namespace ICD.Common.Utils.Tests.Json
|
||||
Assert.AreEqual("test message", messageName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeTypeTest()
|
||||
{
|
||||
const string json = "{\"test\":10}";
|
||||
|
||||
JObject root = JObject.Parse(json);
|
||||
JToken token = root["test"];
|
||||
|
||||
int value = (int)JsonUtils.Deserialize(typeof(int), token);
|
||||
|
||||
Assert.AreEqual(10, value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeTestSerializerTest()
|
||||
{
|
||||
const string json = "{\"test\":10}";
|
||||
|
||||
JObject root = JObject.Parse(json);
|
||||
JToken token = root["test"];
|
||||
|
||||
int value = (int)JsonUtils.Deserialize(typeof(int), token, new JsonSerializer());
|
||||
|
||||
Assert.AreEqual(10, value);
|
||||
}
|
||||
|
||||
public sealed class TestSerializable
|
||||
{
|
||||
private const string PROPERTY_NAME = "Test";
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
#else
|
||||
@@ -149,5 +151,75 @@ namespace ICD.Common.Utils.Tests
|
||||
// Everything else
|
||||
Assert.AreEqual(10, ReflectionUtils.ChangeType("10", typeof(int)));
|
||||
}
|
||||
|
||||
#region Subscription Tests
|
||||
|
||||
[Test]
|
||||
public void SubscribeEventTest()
|
||||
{
|
||||
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
Delegate del = ReflectionUtils.SubscribeEvent<IntEventArgs>(this, eventInfo, IncrementCount);
|
||||
|
||||
Assert.NotNull(del);
|
||||
|
||||
m_Count = 0;
|
||||
OnIncrementCount.Raise(this, new IntEventArgs(10));
|
||||
|
||||
Assert.AreEqual(10, m_Count);
|
||||
|
||||
OnIncrementCount = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscribeEventMethodInfoTest()
|
||||
{
|
||||
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
|
||||
MethodInfo methodInfo =
|
||||
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
|
||||
|
||||
Assert.NotNull(del);
|
||||
|
||||
m_Count = 0;
|
||||
OnIncrementCount.Raise(this, new IntEventArgs(10));
|
||||
|
||||
Assert.AreEqual(10, m_Count);
|
||||
|
||||
OnIncrementCount = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnsubscribeEventTest()
|
||||
{
|
||||
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
|
||||
MethodInfo methodInfo =
|
||||
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
|
||||
|
||||
Assert.NotNull(del);
|
||||
|
||||
m_Count = 0;
|
||||
|
||||
ReflectionUtils.UnsubscribeEvent(this, eventInfo, del);
|
||||
|
||||
OnIncrementCount.Raise(this, new IntEventArgs(10));
|
||||
|
||||
Assert.AreEqual(0, m_Count);
|
||||
}
|
||||
|
||||
// Event has to be public
|
||||
public event EventHandler<IntEventArgs> OnIncrementCount;
|
||||
|
||||
private int m_Count;
|
||||
|
||||
private void IncrementCount(object sender, IntEventArgs args)
|
||||
{
|
||||
m_Count += args.Data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a buffer for storing items to be raised in order in a new thread.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class AsyncEventQueue<T> : IEnumerable<T>, ICollection, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised to handle to the next item in the queue.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnItemDequeued;
|
||||
|
||||
private readonly Queue<T> m_Queue;
|
||||
|
||||
private readonly SafeCriticalSection m_QueueSection;
|
||||
private readonly SafeCriticalSection m_ProcessSection;
|
||||
|
||||
#region Properties
|
||||
|
||||
public int Count { get { return m_QueueSection.Execute(() => m_Queue.Count); } }
|
||||
|
||||
bool ICollection.IsSynchronized { get { return true; } }
|
||||
|
||||
object ICollection.SyncRoot { get { return this; } }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public AsyncEventQueue()
|
||||
{
|
||||
m_Queue = new Queue<T>();
|
||||
|
||||
m_QueueSection = new SafeCriticalSection();
|
||||
m_ProcessSection = new SafeCriticalSection();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Release resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
OnItemDequeued = null;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues the given item and begins processing the queue.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
m_QueueSection.Execute(() => m_Queue.Enqueue(item));
|
||||
|
||||
ThreadingUtils.SafeInvoke(ProcessQueue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the queued items.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
m_QueueSection.Execute(() => m_Queue.Clear());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Dequeues and raises each item in sequence.
|
||||
/// </summary>
|
||||
private void ProcessQueue()
|
||||
{
|
||||
if (!m_ProcessSection.TryEnter())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
T item;
|
||||
while (m_Queue.Dequeue(out item))
|
||||
OnItemDequeued.Raise(this, new GenericEventArgs<T>(item));
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_ProcessSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable/ICollection
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return m_QueueSection.Execute(() => m_Queue.ToList(m_Queue.Count).GetEnumerator());
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
m_QueueSection.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (T item in this)
|
||||
{
|
||||
array.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_QueueSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,24 @@ namespace ICD.Common.Utils.Collections
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public BiDictionary()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="dict"></param>
|
||||
public BiDictionary(Dictionary<TKey, TValue> dict)
|
||||
{
|
||||
m_KeyToValue = new Dictionary<TKey, TValue>();
|
||||
m_ValueToKey = new Dictionary<TValue, TKey>();
|
||||
|
||||
if (dict == null)
|
||||
return;
|
||||
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in dict)
|
||||
Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
@@ -56,7 +56,16 @@ namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
OnItemDequeued = null;
|
||||
|
||||
m_DequeueTimer.Dispose();
|
||||
m_QueueSection.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
m_DequeueTimer.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_QueueSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
@@ -16,8 +15,6 @@ namespace ICD.Common.Utils.Collections
|
||||
private readonly LinkedList<TContents> m_Collection;
|
||||
private int m_MaxSize;
|
||||
|
||||
private readonly SafeCriticalSection m_CollectionLock;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
@@ -41,13 +38,13 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <summary>
|
||||
/// Gets the number of items in the collection.
|
||||
/// </summary>
|
||||
public int Count { get { return m_CollectionLock.Execute(() => m_Collection.Count); } }
|
||||
public int Count { get { return m_Collection.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// The IsSynchronized Boolean property returns True if the
|
||||
/// collection is designed to be thread safe; otherwise, it returns False.
|
||||
/// </summary>
|
||||
public bool IsSynchronized { get { return true; } }
|
||||
public bool IsSynchronized { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// The SyncRoot property returns an object, which is used for synchronizing
|
||||
@@ -64,7 +61,6 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <param name="maxSize"></param>
|
||||
public ScrollQueue(int maxSize)
|
||||
{
|
||||
m_CollectionLock = new SafeCriticalSection();
|
||||
m_Collection = new LinkedList<TContents>();
|
||||
MaxSize = maxSize;
|
||||
}
|
||||
@@ -76,7 +72,7 @@ namespace ICD.Common.Utils.Collections
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
m_CollectionLock.Execute(() => m_Collection.Clear());
|
||||
m_Collection.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,17 +82,8 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public void Enqueue(TContents item)
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
m_Collection.AddLast(item);
|
||||
Trim();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
}
|
||||
m_Collection.AddLast(item);
|
||||
Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,18 +93,9 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public TContents Dequeue()
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
TContents output = m_Collection.First.Value;
|
||||
m_Collection.RemoveFirst();
|
||||
return output;
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
}
|
||||
TContents output = Peek();
|
||||
m_Collection.RemoveFirst();
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,7 +105,7 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public TContents Peek()
|
||||
{
|
||||
return m_CollectionLock.Execute(() => m_Collection.First.Value);
|
||||
return m_Collection.First.Value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -141,24 +119,15 @@ namespace ICD.Common.Utils.Collections
|
||||
|
||||
public IEnumerator<TContents> GetEnumerator()
|
||||
{
|
||||
return m_CollectionLock.Execute(() => m_Collection.ToList(Count).GetEnumerator());
|
||||
return m_Collection.GetEnumerator();
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array myArr, int index)
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
foreach (TContents item in m_Collection)
|
||||
{
|
||||
foreach (TContents item in m_Collection)
|
||||
{
|
||||
myArr.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
myArr.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,17 +140,8 @@ namespace ICD.Common.Utils.Collections
|
||||
/// </summary>
|
||||
private void Trim()
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
while (Count > MaxSize)
|
||||
m_Collection.RemoveFirst();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
}
|
||||
while (Count > MaxSize)
|
||||
m_Collection.RemoveFirst();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -3,25 +3,37 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for working with JSON.
|
||||
/// </summary>
|
||||
public static class JsonExtensions
|
||||
public static class JsonReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the object value.
|
||||
/// Reads the current token in the reader and deserializes to the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static T ReadAsObject<T>(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
return extends.ReadAsObject<T>(serializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the current token in the reader and deserializes to the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="converter"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteObject(this JsonWriter extends, object value, JsonSerializer serializer,
|
||||
JsonConverter converter)
|
||||
/// <returns></returns>
|
||||
public static T ReadAsObject<T>(this JsonReader extends, JsonSerializer serializer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -29,36 +41,48 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (converter == null)
|
||||
throw new ArgumentNullException("converter");
|
||||
|
||||
JObject jObject = JObject.FromObject(value, serializer);
|
||||
jObject.WriteTo(extends, converter);
|
||||
return serializer.Deserialize<T>(extends);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the type value.
|
||||
/// Reads through the current object token and calls the callback for each property value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="type"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteType(this JsonWriter extends, Type type)
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="readPropertyValue"></param>
|
||||
public static void ReadObject(this JsonReader extends, JsonSerializer serializer,
|
||||
Action<string, JsonReader, JsonSerializer> readPropertyValue)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
extends.WriteNull();
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (readPropertyValue == null)
|
||||
throw new ArgumentNullException("readPropertyValue");
|
||||
|
||||
if (extends.TokenType == JsonToken.Null)
|
||||
return;
|
||||
|
||||
if (extends.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, extends.TokenType));
|
||||
|
||||
while (extends.Read())
|
||||
{
|
||||
if (extends.TokenType == JsonToken.EndObject)
|
||||
break;
|
||||
|
||||
// Get the property
|
||||
if (extends.TokenType != JsonToken.PropertyName)
|
||||
continue;
|
||||
string property = (string)extends.Value;
|
||||
|
||||
// Read into the value
|
||||
extends.Read();
|
||||
|
||||
readPropertyValue(property, extends, serializer);
|
||||
}
|
||||
|
||||
// Find the smallest possible name representation for the type that will still resolve
|
||||
string name = Type.GetType(type.FullName) == null
|
||||
? type.AssemblyQualifiedName
|
||||
: type.FullName;
|
||||
|
||||
extends.WriteValue(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,55 +191,18 @@ namespace ICD.Common.Utils.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// Gets the current value as a guid.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Guid GetValueAsGuid(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="write"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
|
||||
Action<JsonSerializer, JsonWriter, TItem> write)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
if (write == null)
|
||||
throw new ArgumentNullException("write");
|
||||
|
||||
writer.WriteStartArray();
|
||||
{
|
||||
foreach (TItem item in items)
|
||||
write(extends, writer, item);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
string stringValue = extends.GetValueAsString();
|
||||
return new Guid(stringValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -285,90 +272,5 @@ namespace ICD.Common.Utils.Extensions
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of key-value-pairs to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeDictionary<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
|
||||
IEnumerable<KeyValuePair<TKey, TValue>> items)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
writer.WriteStartObject();
|
||||
{
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in items)
|
||||
{
|
||||
writer.WritePropertyName(kvp.Key.ToString());
|
||||
extends.Serialize(writer, kvp.Value);
|
||||
}
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a dictionary of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionary<TKey, TValue>(this JsonSerializer extends,
|
||||
JsonReader reader)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return Enumerable.Empty<KeyValuePair<TKey, TValue>>();
|
||||
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartObject, reader.TokenType));
|
||||
|
||||
return DeserializeDictionaryIterator<TKey, TValue>(extends, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a dictionary of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="reader"></param>
|
||||
private static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionaryIterator<TKey, TValue>(
|
||||
JsonSerializer serializer, JsonReader reader)
|
||||
{
|
||||
// Step into the first key
|
||||
reader.Read();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndObject)
|
||||
{
|
||||
TKey key = (TKey)Convert.ChangeType(reader.Value, typeof(TKey), null);
|
||||
|
||||
// Step into the value
|
||||
reader.Read();
|
||||
|
||||
TValue value = serializer.Deserialize<TValue>(reader);
|
||||
|
||||
yield return new KeyValuePair<TKey, TValue>(key, value);
|
||||
|
||||
// Read out of the last value
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
ICD.Common.Utils/Extensions/JsonWriterExtensions.cs
Normal file
83
ICD.Common.Utils/Extensions/JsonWriterExtensions.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
public static class JsonWriterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the type value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="type"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteType(this JsonWriter extends, Type type)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
extends.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
string name = type.GetMinimalName();
|
||||
extends.WriteValue(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="write"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
|
||||
Action<JsonSerializer, JsonWriter, TItem> write)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
if (write == null)
|
||||
throw new ArgumentNullException("write");
|
||||
|
||||
writer.WriteStartArray();
|
||||
{
|
||||
foreach (TItem item in items)
|
||||
write(extends, writer, item);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,8 @@ namespace ICD.Common.Utils.Extensions
|
||||
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
|
||||
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
|
||||
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
|
||||
private static readonly Dictionary<Type, string> s_TypeToMinimalName;
|
||||
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
@@ -72,6 +74,8 @@ namespace ICD.Common.Utils.Extensions
|
||||
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
|
||||
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
|
||||
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
|
||||
s_TypeToMinimalName = new Dictionary<Type, string>();
|
||||
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,6 +162,19 @@ namespace ICD.Common.Utils.Extensions
|
||||
.Assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is assignable to the given type.
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAssignableTo<T>(this Type from)
|
||||
{
|
||||
if (from == null)
|
||||
throw new ArgumentNullException("from");
|
||||
|
||||
return from.IsAssignableTo(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is assignable to the given type.
|
||||
/// </summary>
|
||||
@@ -307,6 +324,128 @@ namespace ICD.Common.Utils.Extensions
|
||||
return index == -1 ? name : name.Substring(0, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the smallest possible string representation for the given type that
|
||||
/// can be converted back to a Type via Type.GetType(string).
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMinimalName(this Type extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string name;
|
||||
if (!s_TypeToMinimalName.TryGetValue(extends, out name))
|
||||
{
|
||||
// Generics are a pain
|
||||
if (extends.IsGenericType)
|
||||
{
|
||||
string nameWithoutAssemblyDetails = Type.GetType(extends.FullName) == null
|
||||
? extends.GetNameWithoutAssemblyDetails()
|
||||
: extends.FullName;
|
||||
int genericStart = nameWithoutAssemblyDetails.IndexOf('[');
|
||||
if (genericStart < 0)
|
||||
{
|
||||
name = nameWithoutAssemblyDetails;
|
||||
}
|
||||
else
|
||||
{
|
||||
string genericParameterNames =
|
||||
string.Join("],[", extends.GetGenericArguments().Select(t => t.GetMinimalName()).ToArray());
|
||||
int genericEnd = nameWithoutAssemblyDetails.LastIndexOf(']');
|
||||
|
||||
name = new StringBuilder().Append(nameWithoutAssemblyDetails, 0, genericStart + 2)
|
||||
.Append(genericParameterNames)
|
||||
.Append(nameWithoutAssemblyDetails, genericEnd - 1,
|
||||
nameWithoutAssemblyDetails.Length - genericEnd + 1)
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = Type.GetType(extends.FullName) == null
|
||||
? extends.GetNameWithoutAssemblyDetails()
|
||||
: extends.FullName;
|
||||
}
|
||||
|
||||
s_TypeToMinimalName.Add(extends, name);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string representation for the type.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNameWithoutAssemblyDetails(this Type extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string name;
|
||||
if (!s_TypeToNameWithoutAssemblyDetails.TryGetValue(extends, out name))
|
||||
{
|
||||
name = RemoveAssemblyDetails(extends.AssemblyQualifiedName);
|
||||
s_TypeToNameWithoutAssemblyDetails.Add(extends, name);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Taken from Newtonsoft.Json.Utilities.ReflectionUtils
|
||||
/// Removes the assembly details from a type assembly qualified name.
|
||||
/// </summary>
|
||||
/// <param name="fullyQualifiedTypeName"></param>
|
||||
/// <returns></returns>
|
||||
private static string RemoveAssemblyDetails(string fullyQualifiedTypeName)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// loop through the type name and filter out qualified assembly details from nested type names
|
||||
bool writingAssemblyName = false;
|
||||
bool skippingAssemblyDetails = false;
|
||||
for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
|
||||
{
|
||||
char current = fullyQualifiedTypeName[i];
|
||||
switch (current)
|
||||
{
|
||||
case '[':
|
||||
writingAssemblyName = false;
|
||||
skippingAssemblyDetails = false;
|
||||
builder.Append(current);
|
||||
break;
|
||||
case ']':
|
||||
writingAssemblyName = false;
|
||||
skippingAssemblyDetails = false;
|
||||
builder.Append(current);
|
||||
break;
|
||||
case ',':
|
||||
if (!writingAssemblyName)
|
||||
{
|
||||
writingAssemblyName = true;
|
||||
builder.Append(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
skippingAssemblyDetails = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!skippingAssemblyDetails)
|
||||
{
|
||||
builder.Append(current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type name as it would appear in code.
|
||||
/// </summary>
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
<None Remove="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
<Compile Include="Attributes\AbstractIcdAttribute.cs" />
|
||||
<Compile Include="Attributes\RangeAttribute.cs" />
|
||||
<Compile Include="Collections\BiDictionary.cs" />
|
||||
<Compile Include="Collections\AsyncEventQueue.cs" />
|
||||
<Compile Include="Collections\IcdOrderedDictionary.cs" />
|
||||
<Compile Include="Collections\PriorityQueue.cs" />
|
||||
<Compile Include="Collections\RateLimitedEventQueue.cs" />
|
||||
@@ -106,6 +105,7 @@
|
||||
<Compile Include="Extensions\BoolExtensions.cs" />
|
||||
<Compile Include="Extensions\ByteExtensions.cs" />
|
||||
<Compile Include="Extensions\DayOfWeekExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonWriterExtensions.cs" />
|
||||
<Compile Include="Extensions\ListExtensions.cs" />
|
||||
<Compile Include="Comparers\PredicateEqualityComparer.cs" />
|
||||
<Compile Include="Extensions\MethodInfoExtensions.cs" />
|
||||
@@ -117,6 +117,7 @@
|
||||
<Compile Include="IO\IcdBinaryReader.cs" />
|
||||
<Compile Include="IO\eSeekOrigin.cs" />
|
||||
<Compile Include="IO\IcdStreamWriter.cs" />
|
||||
<Compile Include="Json\ToStringJsonConverter.cs" />
|
||||
<Compile Include="ProcessorUtils.SimplSharp.cs" />
|
||||
<Compile Include="ProcessorUtils.Standard.cs" />
|
||||
<Compile Include="ProgramUtils.SimplSharp.cs" />
|
||||
@@ -154,7 +155,7 @@
|
||||
<Compile Include="Extensions\EnumerableExtensions.cs" />
|
||||
<Compile Include="Extensions\EnumExtensions.cs" />
|
||||
<Compile Include="Extensions\EventHandlerExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonReaderExtensions.cs" />
|
||||
<Compile Include="Extensions\QueueExtensions.cs" />
|
||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||
<Compile Include="Extensions\StringBuilderExtensions.cs" />
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
@@ -18,6 +20,8 @@ namespace ICD.Common.Utils
|
||||
Administrator = 2
|
||||
}
|
||||
|
||||
public static event EventHandler<StringEventArgs> OnConsolePrint;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
|
||||
/// </summary>
|
||||
@@ -41,26 +45,34 @@ namespace ICD.Common.Utils
|
||||
message = string.Format(message, args);
|
||||
|
||||
#if SIMPLSHARP
|
||||
try
|
||||
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpPro)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(message);
|
||||
try
|
||||
{
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse(message);
|
||||
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
PrintLine(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
Print(message);
|
||||
}
|
||||
#else
|
||||
Print(message);
|
||||
#endif
|
||||
|
||||
PrintLine(message);
|
||||
}
|
||||
|
||||
public static void PrintLine(string message)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
CrestronConsole.PrintLine(message);
|
||||
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
CrestronConsole.PrintLine(message);
|
||||
#else
|
||||
Console.WriteLine(message);
|
||||
#endif
|
||||
OnConsolePrint.Raise(null, new StringEventArgs(message + IcdEnvironment.NewLine));
|
||||
}
|
||||
|
||||
public static void PrintLine(string message, params object[] args)
|
||||
@@ -90,10 +102,12 @@ namespace ICD.Common.Utils
|
||||
public static void Print(string message)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
CrestronConsole.Print(message);
|
||||
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
CrestronConsole.Print(message);
|
||||
#else
|
||||
Console.Write(message);
|
||||
#endif
|
||||
OnConsolePrint.Raise(null, new StringEventArgs(message));
|
||||
}
|
||||
|
||||
public static void Print(string message, params object[] args)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Json
|
||||
@@ -10,7 +11,10 @@ namespace ICD.Common.Utils.Json
|
||||
/// Creates a new instance of T.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract T Instantiate();
|
||||
protected virtual T Instantiate()
|
||||
{
|
||||
return ReflectionUtils.CreateInstance<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
@@ -26,12 +30,6 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
WriteJson(writer, (T)value, serializer);
|
||||
}
|
||||
|
||||
@@ -50,7 +48,9 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
@@ -113,30 +113,15 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
T output = default(T);
|
||||
bool instantiated = false;
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return default(T);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.EndObject)
|
||||
break;
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, reader.TokenType));
|
||||
|
||||
if (!instantiated)
|
||||
{
|
||||
instantiated = true;
|
||||
output = Instantiate();
|
||||
}
|
||||
T output = Instantiate();
|
||||
|
||||
// Get the property
|
||||
if (reader.TokenType != JsonToken.PropertyName)
|
||||
continue;
|
||||
string property = (string)reader.Value;
|
||||
|
||||
// Read into the value
|
||||
reader.Read();
|
||||
|
||||
ReadProperty(property, reader, output, serializer);
|
||||
}
|
||||
reader.ReadObject(serializer, (p, r, s) => ReadProperty(p, r, output, s));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -22,28 +22,6 @@ namespace ICD.Common.Utils.Json
|
||||
private const string MESSAGE_NAME_PROPERTY = "m";
|
||||
private const string MESSAGE_DATA_PROPERTY = "d";
|
||||
|
||||
/// <summary>
|
||||
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public static void CacheType<T>()
|
||||
where T : new()
|
||||
{
|
||||
CacheType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
|
||||
/// </summary>
|
||||
public static void CacheType(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance(type));
|
||||
JsonConvert.DeserializeObject(serialized, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the token as a DateTime value.
|
||||
/// </summary>
|
||||
@@ -87,31 +65,6 @@ namespace ICD.Common.Utils.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pretty-prints the JSON document.
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
[PublicAPI]
|
||||
public static void Print(string json)
|
||||
{
|
||||
if (json == null)
|
||||
throw new ArgumentNullException("json");
|
||||
|
||||
string formatted = Format(json);
|
||||
IcdConsole.PrintLine(formatted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given item and pretty-prints to JSON.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[PublicAPI]
|
||||
public static void Print(object value)
|
||||
{
|
||||
string formatted = Format(value);
|
||||
IcdConsole.PrintLine(formatted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given item and formats the JSON into a human-readable form.
|
||||
/// </summary>
|
||||
@@ -234,6 +187,22 @@ namespace ICD.Common.Utils.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes to json, wrapping the object with a message property to differentiate between messages.
|
||||
/// E.g.
|
||||
/// { a = 1 }
|
||||
/// Becomes
|
||||
/// { m = "Test", d = { a = 1 } }
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="messageName"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static string SerializeMessage(object value, string messageName)
|
||||
{
|
||||
return SerializeMessage(w => new JsonSerializer().Serialize(w, value), messageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes to json, wrapping the object with a message property to differentiate between messages.
|
||||
/// E.g.
|
||||
@@ -317,44 +286,5 @@ namespace ICD.Common.Utils.Json
|
||||
},
|
||||
json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the given token based on the known type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize(Type type, JToken token)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (token == null)
|
||||
throw new ArgumentNullException("token");
|
||||
|
||||
return Deserialize(type, token, new JsonSerializer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the given token based on the known type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize(Type type, JToken token, JsonSerializer serializer)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (token == null)
|
||||
throw new ArgumentNullException("token");
|
||||
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
using (JTokenReader jsonReader = new JTokenReader(token))
|
||||
return serializer.Deserialize(jsonReader, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
89
ICD.Common.Utils/Json/ToStringJsonConverter.cs
Normal file
89
ICD.Common.Utils/Json/ToStringJsonConverter.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
#else
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Simply reads/writes values from/to JSON as their string representation.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class ToStringJsonConverter : JsonConverter
|
||||
{
|
||||
private static readonly Dictionary<Type, MethodInfo> s_ParseMethods;
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
/// </summary>
|
||||
static ToStringJsonConverter()
|
||||
{
|
||||
s_ParseMethods = new Dictionary<Type, MethodInfo>();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
MethodInfo parse = GetParseMethod(objectType);
|
||||
if (parse != null)
|
||||
return parse.Invoke(null, new[] {reader.Value});
|
||||
|
||||
throw new ArgumentException(
|
||||
string.Format("{0} does not have a 'static {0} Parse(string)' method.", objectType.Name),
|
||||
"objectType");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[CanBeNull]
|
||||
private static MethodInfo GetParseMethod(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
MethodInfo output;
|
||||
if (!s_ParseMethods.TryGetValue(type, out output))
|
||||
{
|
||||
|
||||
output = type
|
||||
#if SIMPLSHARP
|
||||
.GetCType()
|
||||
.GetMethod("Parse",
|
||||
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
|
||||
CType.DefaultBinder,
|
||||
new CType[] {typeof(string)},
|
||||
new ParameterModifier[] {});
|
||||
#else
|
||||
.GetTypeInfo()
|
||||
.GetMethod("Parse",
|
||||
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
|
||||
Type.DefaultBinder,
|
||||
new[] {typeof(string)},
|
||||
new ParameterModifier[] {});
|
||||
#endif
|
||||
|
||||
s_ParseMethods.Add(type, output);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,5 @@ using System.Reflection;
|
||||
[assembly: AssemblyTitle("ICD.Common.Utils")]
|
||||
[assembly: AssemblyCompany("ICD Systems")]
|
||||
[assembly: AssemblyProduct("ICD.Common.Utils")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2018")]
|
||||
[assembly: AssemblyVersion("8.3.0.0")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2019")]
|
||||
[assembly: AssemblyVersion("9.2.0.0")]
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
@@ -97,23 +98,23 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there is a path from the given root to the given child node.
|
||||
/// Returns true if there is a path from the given root to the given destination node.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="child"></param>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="getChildren"></param>
|
||||
/// <returns></returns>
|
||||
public static bool BreadthFirstSearch<T>(T root, T child, Func<T, IEnumerable<T>> getChildren)
|
||||
public static bool BreadthFirstSearch<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren)
|
||||
{
|
||||
if (getChildren == null)
|
||||
throw new ArgumentNullException("getChildren");
|
||||
|
||||
return BreadthFirstSearchPath(root, child, getChildren) != null;
|
||||
return BreadthFirstSearch(root, destination, getChildren, EqualityComparer<T>.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there is a path from the given root to the given child node.
|
||||
/// Returns true if there is a path from the given root to the given destination node.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
@@ -159,9 +160,9 @@ namespace ICD.Common.Utils
|
||||
Queue<T> process = new Queue<T>();
|
||||
process.Enqueue(root);
|
||||
|
||||
while (process.Count > 0)
|
||||
T current;
|
||||
while (process.Dequeue(out current))
|
||||
{
|
||||
T current = process.Dequeue();
|
||||
yield return current;
|
||||
|
||||
foreach (T child in getChildren(current))
|
||||
@@ -214,10 +215,9 @@ namespace ICD.Common.Utils
|
||||
|
||||
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer);
|
||||
|
||||
while (queue.Count > 0)
|
||||
T current;
|
||||
while (queue.Dequeue(out current))
|
||||
{
|
||||
T current = queue.Dequeue();
|
||||
|
||||
foreach (T node in getChildren(current))
|
||||
{
|
||||
if (nodeParents.ContainsKey(node))
|
||||
|
||||
@@ -337,8 +337,9 @@ namespace ICD.Common.Utils
|
||||
if (valueType.IsIntegerNumeric())
|
||||
return Enum.ToObject(type, value);
|
||||
|
||||
if (value is string)
|
||||
return Enum.Parse(type, value as string, false);
|
||||
string valueAsString = value as string;
|
||||
if (valueAsString != null)
|
||||
return Enum.Parse(type, valueAsString, false);
|
||||
}
|
||||
|
||||
return Convert.ChangeType(value, type, null);
|
||||
@@ -352,12 +353,56 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the event on the given instance using the handler and callback method.
|
||||
/// Subscribes to the event on the given instance using the event handler.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance with the event. Null for static types.</param>
|
||||
/// <param name="eventInfo">The EventInfo for the event.</param>
|
||||
/// <param name="handler">The instance with the callback MethodInfo. Null for static types.</param>
|
||||
/// <param name="callback">The MethodInfo for the callback method.</param>
|
||||
/// <param name="eventHandler">The EventHandler for the callback.</param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, Action<object> eventHandler)
|
||||
{
|
||||
if (eventInfo == null)
|
||||
throw new ArgumentNullException("eventInfo");
|
||||
|
||||
if (eventHandler == null)
|
||||
throw new ArgumentNullException("eventHandler");
|
||||
|
||||
object handler = eventHandler.Target;
|
||||
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
|
||||
|
||||
return SubscribeEvent(instance, eventInfo, handler, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the event on the given instance using the event handler.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance with the event. Null for static types.</param>
|
||||
/// <param name="eventInfo">The EventInfo for the event.</param>
|
||||
/// <param name="eventHandler">The EventHandler for the callback.</param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate SubscribeEvent<T>(object instance, EventInfo eventInfo, Action<object, T> eventHandler)
|
||||
{
|
||||
if (eventInfo == null)
|
||||
throw new ArgumentNullException("eventInfo");
|
||||
|
||||
if (eventHandler == null)
|
||||
throw new ArgumentNullException("eventHandler");
|
||||
|
||||
object handler = eventHandler.Target;
|
||||
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
|
||||
|
||||
return SubscribeEvent(instance, eventInfo, handler, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the event on the given instance using the handler and eventHandler method.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance with the event. Null for static types.</param>
|
||||
/// <param name="eventInfo">The EventInfo for the event.</param>
|
||||
/// <param name="handler">The instance with the eventHandler MethodInfo. Null for static types.</param>
|
||||
/// <param name="callback">The MethodInfo for the eventHandler method.</param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, object handler, MethodInfo callback)
|
||||
|
||||
@@ -12,8 +12,7 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
private readonly object m_Instance;
|
||||
|
||||
private readonly List<string> m_PropertyOrder;
|
||||
private readonly Dictionary<string, string> m_PropertyValues;
|
||||
private readonly List<KeyValuePair<string, string>> m_PropertyOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
@@ -23,8 +22,7 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
m_Instance = instance;
|
||||
|
||||
m_PropertyOrder = new List<string>();
|
||||
m_PropertyValues = new Dictionary<string, string>();
|
||||
m_PropertyOrder = new List<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,14 +30,10 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AppendProperty(string name, object value)
|
||||
public ReprBuilder AppendProperty(string name, object value)
|
||||
{
|
||||
m_PropertyOrder.Remove(name);
|
||||
m_PropertyOrder.Add(name);
|
||||
|
||||
string valueString = GetValueStringRepresentation(value);
|
||||
|
||||
m_PropertyValues[name] = valueString;
|
||||
return AppendPropertyRaw(name, valueString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,12 +41,10 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AppendPropertyRaw(string name, string value)
|
||||
public ReprBuilder AppendPropertyRaw(string name, string value)
|
||||
{
|
||||
m_PropertyOrder.Remove(name);
|
||||
m_PropertyOrder.Add(name);
|
||||
|
||||
m_PropertyValues[name] = value;
|
||||
m_PropertyOrder.Add(new KeyValuePair<string, string>(name, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,7 +54,7 @@ namespace ICD.Common.Utils
|
||||
public override string ToString()
|
||||
{
|
||||
if (m_Instance == null)
|
||||
return GetValueStringRepresentation(m_Instance);
|
||||
return GetValueStringRepresentation(null);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -71,12 +63,11 @@ namespace ICD.Common.Utils
|
||||
|
||||
for (int index = 0; index < m_PropertyOrder.Count; index++)
|
||||
{
|
||||
string property = m_PropertyOrder[index];
|
||||
builder.Append(property);
|
||||
builder.Append('=');
|
||||
KeyValuePair<string, string> pair = m_PropertyOrder[index];
|
||||
|
||||
string valueString = m_PropertyValues[property];
|
||||
builder.Append(valueString);
|
||||
builder.Append(pair.Key);
|
||||
builder.Append('=');
|
||||
builder.Append(pair.Value);
|
||||
|
||||
if (index < m_PropertyOrder.Count - 1)
|
||||
builder.Append(", ");
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace ICD.Common.Utils
|
||||
private const char INTERSECT = '+';
|
||||
|
||||
private readonly List<string[]> m_Rows;
|
||||
private readonly SafeCriticalSection m_RowsSection;
|
||||
private readonly string[] m_Columns;
|
||||
|
||||
/// <summary>
|
||||
@@ -39,7 +38,6 @@ namespace ICD.Common.Utils
|
||||
public TableBuilder(params string[] columns)
|
||||
{
|
||||
m_Rows = new List<string[]>();
|
||||
m_RowsSection = new SafeCriticalSection();
|
||||
m_Columns = columns;
|
||||
}
|
||||
|
||||
@@ -49,9 +47,10 @@ namespace ICD.Common.Utils
|
||||
/// Clears all of the rows.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void ClearRows()
|
||||
public TableBuilder ClearRows()
|
||||
{
|
||||
m_RowsSection.Execute(() => m_Rows.Clear());
|
||||
m_Rows.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -59,11 +58,11 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
[PublicAPI]
|
||||
public void AddRow(params object[] row)
|
||||
public TableBuilder AddRow(params object[] row)
|
||||
{
|
||||
string[] stringRow = row.Select(o => string.Format("{0}", o))
|
||||
.ToArray();
|
||||
AddRow(stringRow);
|
||||
return AddRow(stringRow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,31 +70,33 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
[PublicAPI]
|
||||
public void AddRow(params string[] row)
|
||||
public TableBuilder AddRow(params string[] row)
|
||||
{
|
||||
if (row != null && row.Length != m_Columns.Length)
|
||||
throw new ArgumentException("Row must match columns length.");
|
||||
|
||||
m_RowsSection.Execute(() => m_Rows.Add(row));
|
||||
m_Rows.Add(row);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an empty row to the builder.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void AddEmptyRow()
|
||||
public TableBuilder AddEmptyRow()
|
||||
{
|
||||
AddRow(new string[m_Columns.Length]);
|
||||
return AddRow(new string[m_Columns.Length]);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public void AddSeparator()
|
||||
public TableBuilder AddSeparator()
|
||||
{
|
||||
AddRow(null);
|
||||
return AddRow(null);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public void AddHeader(params string[] row)
|
||||
public TableBuilder AddHeader(params string[] row)
|
||||
{
|
||||
if (row.Length != m_Columns.Length)
|
||||
throw new ArgumentException("Row must match columns length.");
|
||||
@@ -103,6 +104,8 @@ namespace ICD.Common.Utils
|
||||
AddSeparator();
|
||||
AddRow(row);
|
||||
AddSeparator();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,30 +115,21 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
m_RowsSection.Enter();
|
||||
int[] columnWidths = GetColumnWidths();
|
||||
|
||||
try
|
||||
AppendRow(sb, m_Columns, columnWidths);
|
||||
AppendSeparator(sb, columnWidths);
|
||||
|
||||
foreach (string[] row in m_Rows)
|
||||
{
|
||||
int[] columnWidths = GetColumnWidths();
|
||||
|
||||
AppendRow(sb, m_Columns, columnWidths);
|
||||
AppendSeparator(sb, columnWidths);
|
||||
|
||||
foreach (string[] row in m_Rows)
|
||||
{
|
||||
if (row == null)
|
||||
AppendSeparator(sb, columnWidths);
|
||||
else
|
||||
AppendRow(sb, row, columnWidths);
|
||||
}
|
||||
|
||||
AppendSeparator(sb, columnWidths);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_RowsSection.Leave();
|
||||
if (row == null)
|
||||
AppendSeparator(sb, columnWidths);
|
||||
else
|
||||
AppendRow(sb, row, columnWidths);
|
||||
}
|
||||
|
||||
AppendSeparator(sb, columnWidths);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -85,12 +85,12 @@ namespace ICD.Common.Utils.Timers
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
Stop();
|
||||
m_Timer.Dispose();
|
||||
|
||||
m_Callback = null;
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -160,7 +160,8 @@ namespace ICD.Common.Utils.Timers
|
||||
// Essentially the meat of this class. There's some weirdness with the garbage collector where
|
||||
// the reference to the timer will be cleared, and eventually the CTimer will call the callback
|
||||
// despite being stopped/disposed.
|
||||
if (m_Timer == null
|
||||
if (IsDisposed ||
|
||||
m_Timer == null
|
||||
#if SIMPLSHARP
|
||||
|| m_Timer.Disposed
|
||||
#endif
|
||||
|
||||
@@ -72,7 +72,12 @@ namespace ICD.Common.Utils.Xml
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
return DeserializeObject(type, reader);
|
||||
{
|
||||
if (reader.ReadToNextElement())
|
||||
return DeserializeObject(type, reader);
|
||||
|
||||
throw new FormatException("Expected element in XML");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user