You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/08/28 14:49:47 UTC
[29/41] ignite git commit: IGNITE-1302: Moving some common .Net
classes to Ignite.
IGNITE-1302: Moving some common .Net classes to Ignite.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/8df6b935
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/8df6b935
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/8df6b935
Branch: refs/heads/ignite-1093
Commit: 8df6b935c32d8b801ead4deb0470f84df435ff5a
Parents: 824cfa4
Author: Pavel Tupitsyn <pt...@gridgain.com>
Authored: Wed Aug 26 15:55:24 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Wed Aug 26 15:55:24 2015 +0300
----------------------------------------------------------------------
.../Apache.Ignite.Core.csproj | 22 ++
.../Common/AsyncSupportedAttribute.cs | 33 +++
.../Apache.Ignite.Core/Common/IAsyncSupport.cs | 52 ++++
.../dotnet/Apache.Ignite.Core/Common/IFuture.cs | 115 ++++++++
.../Common/IgniteException.cs | 66 +++++
.../Impl/Collections/CollectionExtensions.cs | 45 +++
.../Impl/Collections/MultiValueDictionary.cs | 143 ++++++++++
.../Impl/Collections/ReadOnlyCollection.cs | 102 +++++++
.../Impl/Collections/ReadOnlyDictionary.cs | 149 ++++++++++
.../Impl/Common/AsyncResult.cs | 71 +++++
.../Impl/Common/CompletedAsyncResult.cs | 70 +++++
.../Common/CopyOnWriteConcurrentDictionary.cs | 70 +++++
.../Impl/Common/DelegateConverter.cs | 253 ++++++++++++++++
.../Apache.Ignite.Core/Impl/Common/Future.cs | 286 +++++++++++++++++++
.../Impl/Common/FutureType.cs | 52 ++++
.../Impl/Common/GridArgumentCheck.cs | 76 +++++
.../Impl/Common/IFutureConverter.cs | 32 +++
.../Impl/Common/IFutureInternal.cs | 45 +++
.../Impl/Common/LoadedAssembliesResolver.cs | 96 +++++++
.../Impl/Common/TypeCaster.cs | 72 +++++
20 files changed, 1850 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 658e5fb..12e335a 100644
--- a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -16,6 +16,7 @@
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Debug\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
@@ -26,6 +27,7 @@
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Debug\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
@@ -47,7 +49,26 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Common\IgniteException.cs" />
+ <Compile Include="Common\IAsyncSupport.cs" />
+ <Compile Include="Common\IFuture.cs" />
<Compile Include="Ignition.cs" />
+ <Compile Include="Common\AsyncSupportedAttribute.cs" />
+ <Compile Include="Impl\Collections\CollectionExtensions.cs" />
+ <Compile Include="Impl\Collections\MultiValueDictionary.cs" />
+ <Compile Include="Impl\Collections\ReadOnlyCollection.cs" />
+ <Compile Include="Impl\Collections\ReadOnlyDictionary.cs" />
+ <Compile Include="Impl\Common\AsyncResult.cs" />
+ <Compile Include="Impl\Common\CompletedAsyncResult.cs" />
+ <Compile Include="Impl\Common\CopyOnWriteConcurrentDictionary.cs" />
+ <Compile Include="Impl\Common\DelegateConverter.cs" />
+ <Compile Include="Impl\Common\Future.cs" />
+ <Compile Include="Impl\Common\FutureType.cs" />
+ <Compile Include="Impl\Common\GridArgumentCheck.cs" />
+ <Compile Include="Impl\Common\IFutureConverter.cs" />
+ <Compile Include="Impl\Common\IFutureInternal.cs" />
+ <Compile Include="Impl\Common\LoadedAssembliesResolver.cs" />
+ <Compile Include="Impl\Common\TypeCaster.cs" />
<Compile Include="Impl\Handle\Handle.cs" />
<Compile Include="Impl\Handle\HandleRegistry.cs" />
<Compile Include="Impl\Handle\IHandle.cs" />
@@ -64,6 +85,7 @@
<Compile Include="Impl\Portable\IO\IPortableStream.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs
new file mode 100644
index 0000000..094a93c
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/AsyncSupportedAttribute.cs
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Common
+{
+ using System;
+
+ /// <summary>
+ /// Attribute to indicate that method can be executed asynchronously if async mode is enabled.
+ /// To enable async mode, invoke <see cref="IAsyncSupport{TWithAsync}.WithAsync"/> method on the API.
+ /// The future for the async method can be retrieved via
+ /// <see cref="IFuture{T}"/> right after the execution of an asynchronous method.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Method)]
+ public sealed class AsyncSupportedAttribute : Attribute
+ {
+ // No-op.
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs
new file mode 100644
index 0000000..f6b6551
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IAsyncSupport.cs
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Common
+{
+ /// <summary>
+ /// Allows to enable asynchronous mode on Grid APIs.
+ /// </summary>
+ /// <typeparam name="TWithAsync">Type of WithAsync method result.</typeparam>
+ public interface IAsyncSupport<out TWithAsync> where TWithAsync : IAsyncSupport<TWithAsync>
+ {
+ /// <summary>
+ /// Gets component with asynchronous mode enabled.
+ /// </summary>
+ /// <returns>Component with asynchronous mode enabled.</returns>
+ TWithAsync WithAsync();
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is in asynchronous mode.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if asynchronous mode is enabled.
+ /// </value>
+ bool IsAsync { get; }
+
+ /// <summary>
+ /// Gets and resets future for previous asynchronous operation.
+ /// </summary>
+ /// <returns>Future for previous asynchronous operation.</returns>
+ IFuture GetFuture();
+
+ /// <summary>
+ /// Gets and resets future for previous asynchronous operation.
+ /// </summary>
+ /// <returns>Future for previous asynchronous operation.</returns>
+ IFuture<TResult> GetFuture<TResult>();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs
new file mode 100644
index 0000000..2e94cd4
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IFuture.cs
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Common
+{
+ using System;
+ using System.Threading.Tasks;
+
+ /// <summary>
+ /// Non-generic Future. Represents an asynchronous operation that can return a value.
+ /// <para/>
+ /// All members are thread-safe and may be used concurrently from multiple threads.
+ /// </summary>
+ public interface IFuture
+ {
+ /// <summary>
+ /// Gets a value indicating whether this instance is done.
+ /// </summary>
+ bool IsDone
+ {
+ get;
+ }
+
+ /// <summary>
+ /// Gets the future result.
+ /// </summary>
+ /// <returns>Future result.</returns>
+ object Get();
+
+ /// <summary>
+ /// Gets the future result with a timeout.
+ /// </summary>
+ /// <param name="timeout">The timeout.</param>
+ /// <returns>
+ /// Future result, if it is obtained within specified timeout; otherwise, throws <see cref="TimeoutException"/>
+ /// </returns>
+ /// <exception cref="TimeoutException">Thrown if Get operation exceeded specified timeout.</exception>
+ object Get(TimeSpan timeout);
+
+ /// <summary>
+ /// Listens this instance and invokes callback upon future completion.
+ /// </summary>
+ /// <param name="callback">The callback to execute upon future completion.</param>
+ void Listen(Action callback);
+
+ /// <summary>
+ /// Listens this instance and invokes callback upon future completion.
+ /// </summary>
+ /// <param name="callback">The callback to execute upon future completion.</param>
+ void Listen(Action<IFuture> callback);
+
+ /// <summary>
+ /// Gets an IAsyncResult indicating the state of this Future.
+ /// </summary>
+ /// <returns>Future state representation in form of IAsyncResult.</returns>
+ IAsyncResult ToAsyncResult();
+
+ /// <summary>
+ /// Gets a Task that returns the result of this Future.
+ /// </summary>
+ /// <returns>Task that completes when this future gets done and returns the result.</returns>
+ Task<object> ToTask();
+ }
+
+ /// <summary>
+ /// Generic Future. Represents an asynchronous operation that can return a value.
+ /// <para/>
+ /// All members are thread-safe and may be used concurrently from multiple threads.
+ /// </summary>
+ /// <typeparam name="T">Future result type.</typeparam>
+ public interface IFuture<T> : IFuture
+ {
+ /// <summary>
+ /// Gets the future result.
+ /// </summary>
+ /// <returns>Future result.</returns>
+ new T Get();
+
+ /// <summary>
+ /// Gets the future result with a timeout.
+ /// </summary>
+ /// <param name="timeout">The timeout.</param>
+ /// <returns>
+ /// Future result, if it is obtained within specified timeout; otherwise, throws <see cref="TimeoutException"/>
+ /// </returns>
+ /// <exception cref="TimeoutException">Thrown if Get operation exceeded specified timeout.</exception>
+ new T Get(TimeSpan timeout);
+
+ /// <summary>
+ /// Gets a Task that returns the result of this Future.
+ /// </summary>
+ /// <returns>Task that completes when this future gets done and returns the result.</returns>
+ new Task<T> ToTask();
+
+ /// <summary>
+ /// Listens this instance and invokes callback upon future completion.
+ /// </summary>
+ /// <param name="callback">The callback to execute upon future completion.</param>
+ void Listen(Action<IFuture<T>> callback);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs
new file mode 100644
index 0000000..4626407
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Common/IgniteException.cs
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Common
+{
+ using System;
+ using System.Runtime.Serialization;
+
+ /// <summary>
+ /// General grid exception. Indicates any error condition within Grid.
+ /// </summary>
+ [Serializable]
+ public class IgniteException : Exception
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IgniteException"/> class.
+ /// </summary>
+ public IgniteException()
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IgniteException" /> class.
+ /// </summary>
+ /// <param name="message">The message that describes the error.</param>
+ public IgniteException(string message) : base(message)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IgniteException" /> class.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ /// <param name="cause">The cause.</param>
+ public IgniteException(string message, Exception cause) : base(message, cause)
+ {
+ // No-op.
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IgniteException"/> class.
+ /// </summary>
+ /// <param name="info">Serialization information.</param>
+ /// <param name="ctx">Streaming context.</param>
+ protected IgniteException(SerializationInfo info, StreamingContext ctx) : base(info, ctx)
+ {
+ // No-op.
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs
new file mode 100644
index 0000000..57295cb
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/CollectionExtensions.cs
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Collections
+{
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Collection extension methods.
+ /// </summary>
+ public static class CollectionExtensions
+ {
+ /// <summary>
+ /// Returns a read-only System.Collections.Generic.IDictionary{K, V} wrapper for the current collection.
+ /// </summary>
+ public static IDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dict)
+ {
+ return new ReadOnlyDictionary<TKey, TValue>(dict);
+ }
+
+ /// <summary>
+ /// Returns a read-only System.Collections.Generic.ICollection{K, V} wrapper for the current collection.
+ /// </summary>
+ public static ICollection<T> AsReadOnly<T>(this ICollection<T> col)
+ {
+ var list = col as List<T>;
+
+ return list != null ? (ICollection<T>) list.AsReadOnly() : new ReadOnlyCollection<T>(col);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs
new file mode 100644
index 0000000..bd7e895
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/MultiValueDictionary.cs
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Collections
+{
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Multiple-values-per-key dictionary.
+ /// </summary>
+ public class MultiValueDictionary<TKey, TValue>
+ {
+ /** Inner dictionary */
+ private readonly Dictionary<TKey, object> _dict = new Dictionary<TKey, object>();
+
+ /// <summary>
+ /// Adds a value.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="val">The value.</param>
+ public void Add(TKey key, TValue val)
+ {
+ object val0;
+
+ if (_dict.TryGetValue(key, out val0))
+ {
+ var list = val0 as List<TValue>;
+
+ if (list != null)
+ list.Add(val);
+ else
+ _dict[key] = new List<TValue> {(TValue) val0, val};
+ }
+ else
+ _dict[key] = val;
+ }
+
+ /// <summary>
+ /// Tries the get a value. In case of multiple values for a key, returns the last one.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="val">The value.</param>
+ /// <returns>True if value has been found for specified key; otherwise false.</returns>
+ public bool TryGetValue(TKey key, out TValue val)
+ {
+ object val0;
+
+ if (!_dict.TryGetValue(key, out val0))
+ {
+ val = default(TValue);
+ return false;
+ }
+
+ var list = val0 as List<TValue>;
+
+ if (list != null)
+ val = list[list.Count - 1];
+ else
+ val = (TValue) val0;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Removes the specified value for the specified key.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="val">The value.</param>
+ public void Remove(TKey key, TValue val)
+ {
+ object val0;
+
+ if (!_dict.TryGetValue(key, out val0))
+ return;
+
+ var list = val0 as List<TValue>;
+
+ if (list != null)
+ {
+ list.Remove(val);
+
+ if (list.Count == 0)
+ _dict.Remove(key);
+ }
+ else if (Equals(val0, val))
+ _dict.Remove(key);
+ }
+
+ /// <summary>
+ /// Removes the last value for the specified key and returns it.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="val">The value.</param>
+ /// <returns>True if value has been found for specified key; otherwise false.</returns>
+ public bool TryRemove(TKey key, out TValue val)
+ {
+ object val0;
+
+ if (!_dict.TryGetValue(key, out val0))
+ {
+ val = default(TValue);
+
+ return false;
+ }
+
+ var list = val0 as List<TValue>;
+
+ if (list != null)
+ {
+ var index = list.Count - 1;
+
+ val = list[index];
+
+ list.RemoveAt(index);
+
+ if (list.Count == 0)
+ _dict.Remove(key);
+
+ return true;
+ }
+
+ val = (TValue) val0;
+
+ _dict.Remove(key);
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs
new file mode 100644
index 0000000..23cae6b
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyCollection.cs
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Collections
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Read-only wrapper over ICollection{T}.
+ /// </summary>
+ internal struct ReadOnlyCollection<T> : ICollection<T>
+ {
+ /** Wrapped collection. */
+ private readonly ICollection<T> _col;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ReadOnlyCollection{T}"/> class.
+ /// </summary>
+ public ReadOnlyCollection(ICollection<T> col)
+ {
+ _col = col;
+ }
+
+ /** <inheritdoc /> */
+ public IEnumerator<T> GetEnumerator()
+ {
+ return _col.GetEnumerator();
+ }
+
+ /** <inheritdoc /> */
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable) _col).GetEnumerator();
+ }
+
+ /** <inheritdoc /> */
+ public void Add(T item)
+ {
+ throw GetReadOnlyException();
+ }
+
+ /** <inheritdoc /> */
+ public void Clear()
+ {
+ throw GetReadOnlyException();
+ }
+
+ /** <inheritdoc /> */
+ public bool Contains(T item)
+ {
+ return _col.Contains(item);
+ }
+
+ /** <inheritdoc /> */
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ _col.CopyTo(array, arrayIndex);
+ }
+
+ /** <inheritdoc /> */
+ public bool Remove(T item)
+ {
+ throw GetReadOnlyException();
+ }
+
+ /** <inheritdoc /> */
+ public int Count
+ {
+ get { return _col.Count; }
+ }
+
+ /** <inheritdoc /> */
+ public bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ /// <summary>
+ /// Gets the readonly exception.
+ /// </summary>
+ private static Exception GetReadOnlyException()
+ {
+ return new NotSupportedException("Collection is read-only.");
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs
new file mode 100644
index 0000000..60ec9d0
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Collections/ReadOnlyDictionary.cs
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Collections
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+
+ /// <summary>
+ /// Read-only wrapper over IDictionary{K, V}.
+ /// </summary>
+ internal struct ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
+ {
+ /** Inner dict. */
+ private readonly IDictionary<TKey, TValue> _dict;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ReadOnlyDictionary{K, V}"/> class.
+ /// </summary>
+ /// <param name="dict">The dictionary to wrap.</param>
+ public ReadOnlyDictionary(IDictionary<TKey, TValue> dict)
+ {
+ Debug.Assert(dict != null);
+
+ _dict = dict;
+ }
+
+ /** <inheritdoc /> */
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ return _dict.GetEnumerator();
+ }
+
+ /** <inheritdoc /> */
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable) _dict).GetEnumerator();
+ }
+
+ /** <inheritdoc /> */
+ public void Add(KeyValuePair<TKey, TValue> item)
+ {
+ throw GetReadonlyException();
+ }
+
+ /** <inheritdoc /> */
+ public void Clear()
+ {
+ throw GetReadonlyException();
+ }
+
+ /** <inheritdoc /> */
+ public bool Contains(KeyValuePair<TKey, TValue> item)
+ {
+ return _dict.Contains(item);
+ }
+
+ /** <inheritdoc /> */
+ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ _dict.CopyTo(array, arrayIndex);
+ }
+
+ /** <inheritdoc /> */
+ public bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ throw GetReadonlyException();
+ }
+
+ /** <inheritdoc /> */
+ public int Count
+ {
+ get { return _dict.Count; }
+ }
+
+ /** <inheritdoc /> */
+ public bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ /** <inheritdoc /> */
+ public bool ContainsKey(TKey key)
+ {
+ return _dict.ContainsKey(key);
+ }
+
+ /** <inheritdoc /> */
+ public void Add(TKey key, TValue value)
+ {
+ throw GetReadonlyException();
+ }
+
+ /** <inheritdoc /> */
+ public bool Remove(TKey key)
+ {
+ return _dict.Remove(key);
+ }
+
+ /** <inheritdoc /> */
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ return _dict.TryGetValue(key, out value);
+ }
+
+ /** <inheritdoc /> */
+ public TValue this[TKey key]
+ {
+ get { return _dict[key]; }
+ set { throw GetReadonlyException(); }
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<TKey> Keys
+ {
+ get { return _dict.Keys; }
+ }
+
+ /** <inheritdoc /> */
+ public ICollection<TValue> Values
+ {
+ get { return _dict.Values; }
+ }
+
+ /// <summary>
+ /// Gets the readonly exception.
+ /// </summary>
+ private static Exception GetReadonlyException()
+ {
+ return new NotSupportedException("Dictionary is read-only.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs
new file mode 100644
index 0000000..4e5c396
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/AsyncResult.cs
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Threading;
+ using Apache.Ignite.Core.Common;
+
+ /// <summary>
+ /// Adapts IGridFuture to the IAsyncResult.
+ /// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
+ Justification = "Implementing IDisposable has no point since we return this class as IAsyncResult " +
+ "to the client, and IAsyncResult is not IDisposable.")]
+ public class AsyncResult : IAsyncResult
+ {
+ /** */
+ private readonly ManualResetEvent _waitHandle;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AsyncResult"/> class.
+ /// </summary>
+ /// <param name="fut">The future to wrap.</param>
+ public AsyncResult(IFuture fut)
+ {
+ _waitHandle = new ManualResetEvent(false);
+
+ fut.Listen(() => _waitHandle.Set());
+ }
+
+ /** <inheritdoc /> */
+ public bool IsCompleted
+ {
+ get { return _waitHandle.WaitOne(0); }
+ }
+
+ /** <inheritdoc /> */
+ public WaitHandle AsyncWaitHandle
+ {
+ get { return _waitHandle; }
+ }
+
+ /** <inheritdoc /> */
+ public object AsyncState
+ {
+ get { return null; }
+ }
+
+ /** <inheritdoc /> */
+ public bool CompletedSynchronously
+ {
+ get { return false; }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs
new file mode 100644
index 0000000..14195fd
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CompletedAsyncResult.cs
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Threading;
+
+ /// <summary>
+ /// Represents an IAsyncResult that is completed.
+ /// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
+ Justification = "Implementing IDisposable has no point since we return this class as IAsyncResult " +
+ "to the client, and IAsyncResult is not IDisposable.")]
+ public class CompletedAsyncResult : IAsyncResult
+ {
+ /** Singleton instance. */
+ public static readonly IAsyncResult Instance = new CompletedAsyncResult();
+
+ /** */
+ private readonly WaitHandle _asyncWaitHandle = new ManualResetEvent(true);
+
+ /// <summary>
+ /// Prevents a default instance of the <see cref="CompletedAsyncResult"/> class from being created.
+ /// </summary>
+ private CompletedAsyncResult()
+ {
+ // No-op.
+ }
+
+ /** <inheritdoc /> */
+ public bool IsCompleted
+ {
+ get { return true; }
+ }
+
+ /** <inheritdoc /> */
+ public WaitHandle AsyncWaitHandle
+ {
+ get { return _asyncWaitHandle; }
+ }
+
+ /** <inheritdoc /> */
+ public object AsyncState
+ {
+ get { return null; }
+ }
+
+ /** <inheritdoc /> */
+ public bool CompletedSynchronously
+ {
+ get { return false; }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
new file mode 100644
index 0000000..fa785b2
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/CopyOnWriteConcurrentDictionary.cs
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Concurrent dictionary with CopyOnWrite mechanism inside.
+ /// Good for frequent reads / infrequent writes scenarios.
+ /// </summary>
+ public class CopyOnWriteConcurrentDictionary<TKey, TValue>
+ {
+ /** */
+ private volatile Dictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>();
+
+ /// <summary>
+ /// Gets the value associated with the specified key.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="val">The value.</param>
+ /// <returns>true if the dictionary contains an element with the specified key; otherwise, false.</returns>
+ public bool TryGetValue(TKey key, out TValue val)
+ {
+ return _dict.TryGetValue(key, out val);
+ }
+
+ /// <summary>
+ /// Adds a key/value pair if the key does not already exist.
+ /// </summary>
+ /// <param name="key">The key.</param>
+ /// <param name="valueFactory">The function used to generate a value for the key.</param>
+ /// <returns>The value for the key.</returns>
+ public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
+ {
+ lock (this)
+ {
+ TValue res;
+
+ if (_dict.TryGetValue(key, out res))
+ return res;
+
+ var dict0 = new Dictionary<TKey, TValue>(_dict);
+
+ res = valueFactory(key);
+
+ dict0[key] = res;
+
+ _dict = dict0;
+
+ return res;
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
new file mode 100644
index 0000000..7f83588
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/DelegateConverter.cs
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Diagnostics;
+ using System.Linq.Expressions;
+ using System.Reflection;
+ using System.Reflection.Emit;
+
+ /// <summary>
+ /// Converts generic and non-generic delegates.
+ /// </summary>
+ public static class DelegateConverter
+ {
+ /** */
+ private const string DefaultMethodName = "Invoke";
+
+ /// <summary>
+ /// Compiles a function without arguments.
+ /// </summary>
+ /// <param name="targetType">Type of the target.</param>
+ /// <returns>Compiled function that calls specified method on specified target.</returns>
+ public static Func<object, object> CompileFunc(Type targetType)
+ {
+ var method = targetType.GetMethod(DefaultMethodName);
+
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, targetType);
+
+ var callExpr = Expression.Call(targetParamConverted, method);
+ var convertResultExpr = Expression.Convert(callExpr, typeof(object));
+
+ return Expression.Lambda<Func<object, object>>(convertResultExpr, targetParam).Compile();
+ }
+
+ /// <summary>
+ /// Compiles a function with arbitrary number of arguments.
+ /// </summary>
+ /// <typeparam name="T">Resulting delegate type.</typeparam>
+ /// <param name="targetType">Type of the target.</param>
+ /// <param name="argTypes">Argument types.</param>
+ /// <param name="convertToObject">
+ /// Flags that indicate whether func params and/or return value should be converted from/to object.
+ /// </param>
+ /// <param name="methodName">Name of the method.</param>
+ /// <returns>
+ /// Compiled function that calls specified method on specified target.
+ /// </returns>
+ public static T CompileFunc<T>(Type targetType, Type[] argTypes, bool[] convertToObject = null,
+ string methodName = null)
+ where T : class
+ {
+ var method = targetType.GetMethod(methodName ?? DefaultMethodName, argTypes);
+
+ return CompileFunc<T>(targetType, method, argTypes, convertToObject);
+ }
+
+ /// <summary>
+ /// Compiles a function with arbitrary number of arguments.
+ /// </summary>
+ /// <typeparam name="T">Resulting delegate type.</typeparam>
+ /// <param name="method">Method.</param>
+ /// <param name="targetType">Type of the target.</param>
+ /// <param name="argTypes">Argument types.</param>
+ /// <param name="convertToObject">
+ /// Flags that indicate whether func params and/or return value should be converted from/to object.
+ /// </param>
+ /// <returns>
+ /// Compiled function that calls specified method on specified target.
+ /// </returns>
+ public static T CompileFunc<T>(Type targetType, MethodInfo method, Type[] argTypes,
+ bool[] convertToObject = null)
+ where T : class
+ {
+ if (argTypes == null)
+ {
+ var args = method.GetParameters();
+ argTypes = new Type[args.Length];
+
+ for (int i = 0; i < args.Length; i++)
+ argTypes[i] = args[i].ParameterType;
+ }
+
+ Debug.Assert(convertToObject == null || (convertToObject.Length == argTypes.Length + 1));
+ Debug.Assert(method != null);
+
+ targetType = method.IsStatic ? null : (targetType ?? method.DeclaringType);
+
+ var targetParam = Expression.Parameter(typeof(object));
+
+ Expression targetParamConverted = null;
+ ParameterExpression[] argParams;
+ int argParamsOffset = 0;
+
+ if (targetType != null)
+ {
+ targetParamConverted = Expression.Convert(targetParam, targetType);
+ argParams = new ParameterExpression[argTypes.Length + 1];
+ argParams[0] = targetParam;
+ argParamsOffset = 1;
+ }
+ else
+ argParams = new ParameterExpression[argTypes.Length]; // static method
+
+ var argParamsConverted = new Expression[argTypes.Length];
+
+ for (var i = 0; i < argTypes.Length; i++)
+ {
+ if (convertToObject == null || convertToObject[i])
+ {
+ var argParam = Expression.Parameter(typeof (object));
+ argParams[i + argParamsOffset] = argParam;
+ argParamsConverted[i] = Expression.Convert(argParam, argTypes[i]);
+ }
+ else
+ {
+ var argParam = Expression.Parameter(argTypes[i]);
+ argParams[i + argParamsOffset] = argParam;
+ argParamsConverted[i] = argParam;
+ }
+ }
+
+ Expression callExpr = Expression.Call(targetParamConverted, method, argParamsConverted);
+
+ if (convertToObject == null || convertToObject[argTypes.Length])
+ callExpr = Expression.Convert(callExpr, typeof(object));
+
+ return Expression.Lambda<T>(callExpr, argParams).Compile();
+ }
+
+ /// <summary>
+ /// Compiles a generic ctor with arbitrary number of arguments.
+ /// </summary>
+ /// <typeparam name="T">Result func type.</typeparam>
+ /// <param name="type">Type to be created by ctor.</param>
+ /// <param name="argTypes">Argument types.</param>
+ /// <param name="convertResultToObject">if set to <c>true</c> [convert result to object].
+ /// Flag that indicates whether ctor return value should be converted to object.
+ /// </param>
+ /// <returns>
+ /// Compiled generic constructor.
+ /// </returns>
+ public static T CompileCtor<T>(Type type, Type[] argTypes, bool convertResultToObject = true)
+ {
+ var ctor = type.GetConstructor(argTypes);
+
+ Debug.Assert(ctor != null);
+
+ var args = new ParameterExpression[argTypes.Length];
+ var argsConverted = new Expression[argTypes.Length];
+
+ for (var i = 0; i < argTypes.Length; i++)
+ {
+ var arg = Expression.Parameter(typeof(object));
+ args[i] = arg;
+ argsConverted[i] = Expression.Convert(arg, argTypes[i]);
+ }
+
+ Expression ctorExpr = Expression.New(ctor, argsConverted); // ctor takes args of specific types
+
+ if (convertResultToObject)
+ ctorExpr = Expression.Convert(ctorExpr, typeof (object)); // convert ctor result to object
+
+ return Expression.Lambda<T>(ctorExpr, args).Compile(); // lambda takes args as objects
+ }
+
+ /// <summary>
+ /// Compiles the field setter.
+ /// </summary>
+ /// <param name="field">The field.</param>
+ /// <returns>Compiled field setter.</returns>
+ public static Action<object, object> CompileFieldSetter(FieldInfo field)
+ {
+ Debug.Assert(field != null);
+ Debug.Assert(field.DeclaringType != null); // non-static
+
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType);
+
+ var valParam = Expression.Parameter(typeof(object));
+ var valParamConverted = Expression.Convert(valParam, field.FieldType);
+
+ var assignExpr = Expression.Call(GetWriteFieldMethod(field), targetParamConverted, valParamConverted);
+
+ return Expression.Lambda<Action<object, object>>(assignExpr, targetParam, valParam).Compile();
+ }
+
+ /// <summary>
+ /// Compiles the property setter.
+ /// </summary>
+ /// <param name="prop">The property.</param>
+ /// <returns>Compiled property setter.</returns>
+ public static Action<object, object> CompilePropertySetter(PropertyInfo prop)
+ {
+ Debug.Assert(prop != null);
+ Debug.Assert(prop.DeclaringType != null); // non-static
+
+ var targetParam = Expression.Parameter(typeof(object));
+ var targetParamConverted = Expression.Convert(targetParam, prop.DeclaringType);
+
+ var valParam = Expression.Parameter(typeof(object));
+ var valParamConverted = Expression.Convert(valParam, prop.PropertyType);
+
+ var fld = Expression.Property(targetParamConverted, prop);
+
+ var assignExpr = Expression.Assign(fld, valParamConverted);
+
+ return Expression.Lambda<Action<object, object>>(assignExpr, targetParam, valParam).Compile();
+ }
+
+ /// <summary>
+ /// Gets a method to write a field (including private and readonly).
+ /// NOTE: Expression Trees can't write readonly fields.
+ /// </summary>
+ /// <param name="field">The field.</param>
+ /// <returns>Resulting MethodInfo.</returns>
+ public static DynamicMethod GetWriteFieldMethod(FieldInfo field)
+ {
+ Debug.Assert(field != null);
+
+ var module = Assembly.GetExecutingAssembly().GetModules()[0];
+
+ var method = new DynamicMethod(string.Empty, null, new[] { field.DeclaringType, field.FieldType }, module,
+ true);
+
+ var il = method.GetILGenerator();
+
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Stfld, field);
+ il.Emit(OpCodes.Ret);
+
+ return method;
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs
new file mode 100644
index 0000000..c62cfd2
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/Future.cs
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+
+ /// <summary>
+ /// Grid future implementation.
+ /// </summary>
+ [SuppressMessage("ReSharper", "ParameterHidesMember")]
+ public sealed class Future<T> : IFutureInternal, IFuture<T>
+ {
+ /** Converter. */
+ private readonly IFutureConverter<T> _converter;
+
+ /** Result. */
+ private T _res;
+
+ /** Caught cxception. */
+ private Exception _err;
+
+ /** Done flag. */
+ private volatile bool _done;
+
+ /** Listener(s). Either Action or List{Action}. */
+ private object _callbacks;
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="converter">Future result marshaller and converter.</param>
+ public Future(IFutureConverter<T> converter = null)
+ {
+ _converter = converter;
+ }
+
+ /** <inheritdoc/> */
+ public bool IsDone
+ {
+ get { return _done; }
+ }
+
+ /** <inheritdoc/> */
+ public T Get()
+ {
+ if (!_done)
+ {
+ lock (this)
+ {
+ while (!_done)
+ Monitor.Wait(this);
+ }
+ }
+
+ return Get0();
+ }
+
+ /** <inheritdoc/> */
+ public T Get(TimeSpan timeout)
+ {
+ long ticks = timeout.Ticks;
+
+ if (ticks < 0)
+ throw new ArgumentException("Timeout cannot be negative.");
+
+ if (ticks == 0)
+ return Get();
+
+ if (!_done)
+ {
+ // Fallback to locked mode.
+ lock (this)
+ {
+ long endTime = DateTime.Now.Ticks + ticks;
+
+ if (!_done)
+ {
+ while (true)
+ {
+ Monitor.Wait(this, timeout);
+
+ if (_done)
+ break;
+
+ ticks = endTime - DateTime.Now.Ticks;
+
+ if (ticks <= 0)
+ throw new TimeoutException("Timeout waiting for future completion.");
+
+ timeout = TimeSpan.FromTicks(ticks);
+ }
+ }
+ }
+ }
+
+ return Get0();
+ }
+
+ /** <inheritdoc/> */
+ public void Listen(Action callback)
+ {
+ Listen((Action<IFuture<T>>) (fut => callback()));
+ }
+
+ /** <inheritdoc/> */
+ public void Listen(Action<IFuture> callback)
+ {
+ Listen((Action<IFuture<T>>)callback);
+ }
+
+ /** <inheritdoc/> */
+ public void Listen(Action<IFuture<T>> callback)
+ {
+ GridArgumentCheck.NotNull(callback, "callback");
+
+ if (!_done)
+ {
+ lock (this)
+ {
+ if (!_done)
+ {
+ AddCallback(callback);
+
+ return;
+ }
+ }
+ }
+
+ callback(this);
+ }
+
+ /// <summary>
+ /// Get result or throw an error.
+ /// </summary>
+ private T Get0()
+ {
+ if (_err != null)
+ throw _err;
+
+ return _res;
+ }
+
+ /** <inheritdoc/> */
+ public IAsyncResult ToAsyncResult()
+ {
+ return _done ? CompletedAsyncResult.Instance : new AsyncResult(this);
+ }
+
+ /** <inheritdoc/> */
+ Task<object> IFuture.ToTask()
+ {
+ return Task.Factory.FromAsync(ToAsyncResult(), x => (object) Get());
+ }
+
+ /** <inheritdoc/> */
+ public Task<T> ToTask()
+ {
+ return Task.Factory.FromAsync(ToAsyncResult(), x => Get());
+ }
+
+ /** <inheritdoc/> */
+ object IFuture.Get(TimeSpan timeout)
+ {
+ return Get(timeout);
+ }
+
+ /** <inheritdoc/> */
+ object IFuture.Get()
+ {
+ return Get();
+ }
+
+ /** <inheritdoc /> */
+ public void OnResult(IPortableStream stream)
+ {
+ try
+ {
+ OnResult(_converter.Convert(stream));
+ }
+ catch (Exception ex)
+ {
+ OnError(ex);
+ }
+ }
+
+ /** <inheritdoc /> */
+ public void OnError(Exception err)
+ {
+ OnDone(default(T), err);
+ }
+
+ /** <inheritdoc /> */
+ public void OnNullResult()
+ {
+ OnResult(default(T));
+ }
+
+ /// <summary>
+ /// Set result.
+ /// </summary>
+ /// <param name="res">Result.</param>
+ internal void OnResult(T res)
+ {
+ OnDone(res, null);
+ }
+
+ /// <summary>
+ /// Set future to Done state.
+ /// </summary>
+ /// <param name="res">Result.</param>
+ /// <param name="err">Error.</param>
+ public void OnDone(T res, Exception err)
+ {
+ object callbacks0 = null;
+
+ lock (this)
+ {
+ if (!_done)
+ {
+ _res = res;
+ _err = err;
+
+ _done = true;
+
+ Monitor.PulseAll(this);
+
+ // Notify listeners outside the lock
+ callbacks0 = _callbacks;
+ _callbacks = null;
+ }
+ }
+
+ if (callbacks0 != null)
+ {
+ var list = callbacks0 as List<Action<IFuture<T>>>;
+
+ if (list != null)
+ list.ForEach(x => x(this));
+ else
+ ((Action<IFuture<T>>) callbacks0)(this);
+ }
+ }
+
+ /// <summary>
+ /// Adds a callback.
+ /// </summary>
+ private void AddCallback(Action<IFuture<T>> callback)
+ {
+ if (_callbacks == null)
+ {
+ _callbacks = callback;
+
+ return;
+ }
+
+ var list = _callbacks as List<Action<IFuture<T>>> ??
+ new List<Action<IFuture<T>>> {(Action<IFuture<T>>) _callbacks};
+
+ list.Add(callback);
+
+ _callbacks = list;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs
new file mode 100644
index 0000000..0beff04
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/FutureType.cs
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ /// <summary>
+ /// Future types.
+ /// </summary>
+ public enum FutureType
+ {
+ /** Future type: byte. */
+ Byte = 1,
+
+ /** Future type: boolean. */
+ Bool = 2,
+
+ /** Future type: short. */
+ Short = 3,
+
+ /** Future type: char. */
+ Char = 4,
+
+ /** Future type: int. */
+ Int = 5,
+
+ /** Future type: float. */
+ Float = 6,
+
+ /** Future type: long. */
+ Long = 7,
+
+ /** Future type: double. */
+ Double = 8,
+
+ /** Future type: object. */
+ Object = 9
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs
new file mode 100644
index 0000000..a1fadfe
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/GridArgumentCheck.cs
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// Arguments check helpers.
+ /// </summary>
+ public static class GridArgumentCheck
+ {
+ /// <summary>
+ /// Throws an ArgumentNullException if specified arg is null.
+ /// </summary>
+ /// <param name="arg">The argument.</param>
+ /// <param name="argName">Name of the argument.</param>
+ public static void NotNull(object arg, string argName)
+ {
+ if (arg == null)
+ throw new ArgumentNullException(argName);
+ }
+
+ /// <summary>
+ /// Throws an ArgumentException if specified arg is null or empty string.
+ /// </summary>
+ /// <param name="arg">The argument.</param>
+ /// <param name="argName">Name of the argument.</param>
+ public static void NotNullOrEmpty(string arg, string argName)
+ {
+ if (string.IsNullOrEmpty(arg))
+ throw new ArgumentException(string.Format("'{0}' argument should not be null or empty.", argName),
+ argName);
+ }
+
+ /// <summary>
+ /// Throws an ArgumentException if specified arg is null or empty string.
+ /// </summary>
+ /// <param name="collection">The collection.</param>
+ /// <param name="argName">Name of the argument.</param>
+ public static void NotNullOrEmpty<T>(ICollection<T> collection, string argName)
+ {
+ if (collection == null || collection.Count == 0)
+ throw new ArgumentException(string.Format("'{0}' argument should not be null or empty.", argName),
+ argName);
+ }
+
+ /// <summary>
+ /// Throws an ArgumentException if specified condition is false.
+ /// </summary>
+ /// <param name="condition">Condition.</param>
+ /// <param name="argName">Name of the argument.</param>
+ /// <param name="message">Message.</param>
+ public static void Ensure(bool condition, string argName, string message)
+ {
+ if (!condition)
+ throw new ArgumentException(string.Format("'{0}' argument is invalid: {1}", argName, message),
+ argName);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs
new file mode 100644
index 0000000..4169c61
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureConverter.cs
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using Apache.Ignite.Core.Impl.Portable.IO;
+
+ /// <summary>
+ /// Marshals and converts future value.
+ /// </summary>
+ public interface IFutureConverter<out T>
+ {
+ /// <summary>
+ /// Reads and converts a value.
+ /// </summary>
+ T Convert(IPortableStream stream);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs
new file mode 100644
index 0000000..8547545
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/IFutureInternal.cs
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using Apache.Ignite.Core.Impl.Portable.IO;
+
+ /// <summary>
+ /// Internal future interface.
+ /// </summary>
+ public interface IFutureInternal
+ {
+ /// <summary>
+ /// Set result from stream.
+ /// </summary>
+ /// <param name="stream">Stream.</param>
+ void OnResult(IPortableStream stream);
+
+ /// <summary>
+ /// Set null result.
+ /// </summary>
+ void OnNullResult();
+
+ /// <summary>
+ /// Set error result.
+ /// </summary>
+ /// <param name="err">Exception.</param>
+ void OnError(Exception err);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs
new file mode 100644
index 0000000..c158d5c
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/LoadedAssembliesResolver.cs
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Reflection;
+
+ /// <summary>
+ /// Resolves loaded assemblies by name.
+ /// </summary>
+ public class LoadedAssembliesResolver
+ {
+ // The lazy singleton instance.
+ private static readonly Lazy<LoadedAssembliesResolver> LazyInstance = new Lazy<LoadedAssembliesResolver>();
+
+ // Assemblies map.
+ private volatile Dictionary<string, Assembly> _map;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LoadedAssembliesResolver"/> class.
+ /// </summary>
+ public LoadedAssembliesResolver()
+ {
+ lock (this)
+ {
+ AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
+
+ UpdateMap();
+ }
+ }
+
+ /// <summary>
+ /// Handles the AssemblyLoad event of the AppDomain.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="args">The <see cref="AssemblyLoadEventArgs"/> instance containing the event data.</param>
+ private void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
+ {
+ lock (this)
+ {
+ UpdateMap();
+ }
+ }
+
+ /// <summary>
+ /// Updates the assembly map according to the current list of loaded assemblies.
+ /// </summary>
+ private void UpdateMap()
+ {
+ var assemblies = AppDomain.CurrentDomain.GetAssemblies();
+
+ _map = new Dictionary<string, Assembly>(assemblies.Length);
+
+ foreach (var assembly in assemblies)
+ _map[assembly.FullName] = assembly;
+ }
+
+ /// <summary>
+ /// Gets the singleton instance.
+ /// </summary>
+ public static LoadedAssembliesResolver Instance
+ {
+ get { return LazyInstance.Value; }
+ }
+
+ /// <summary>
+ /// Gets the assembly by name.
+ /// </summary>
+ /// <param name="assemblyName">Name of the assembly.</param>
+ /// <returns>Assembly with specified name, or null.</returns>
+ [SuppressMessage("ReSharper", "InconsistentlySynchronizedField")]
+ public Assembly GetAssembly(string assemblyName)
+ {
+ Assembly asm;
+
+ return _map.TryGetValue(assemblyName, out asm) ? asm : null;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/8df6b935/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs
----------------------------------------------------------------------
diff --git a/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs
new file mode 100644
index 0000000..d0dd2a9
--- /dev/null
+++ b/modules/platform/src/main/dotnet/Apache.Ignite.Core/Impl/Common/TypeCaster.cs
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Impl.Common
+{
+ using System;
+ using System.Linq.Expressions;
+
+ /// <summary>
+ /// Does type casts without extra boxing.
+ /// Should be used when casting compile-time incompatible value types instead of "(T)(object)x".
+ /// </summary>
+ /// <typeparam name="T">Target type</typeparam>
+ public static class TypeCaster<T>
+ {
+ /// <summary>
+ /// Efficiently casts an object from TFrom to T.
+ /// Does not cause boxing for value types.
+ /// </summary>
+ /// <typeparam name="TFrom">Source type to cast from.</typeparam>
+ /// <param name="obj">The object to cast.</param>
+ /// <returns>Casted object.</returns>
+ public static T Cast<TFrom>(TFrom obj)
+ {
+ return Casters<TFrom>.Caster(obj);
+ }
+
+ /// <summary>
+ /// Inner class serving as a cache.
+ /// </summary>
+ private static class Casters<TFrom>
+ {
+ /// <summary>
+ /// Compiled caster delegate.
+ /// </summary>
+ internal static readonly Func<TFrom, T> Caster = Compile();
+
+ /// <summary>
+ /// Compiles caster delegate.
+ /// </summary>
+ private static Func<TFrom, T> Compile()
+ {
+ if (typeof (T) == typeof (TFrom))
+ {
+ // Just return what we have
+ var pExpr = Expression.Parameter(typeof(TFrom));
+
+ return Expression.Lambda<Func<TFrom, T>>(pExpr, pExpr).Compile();
+ }
+
+ var paramExpr = Expression.Parameter(typeof(TFrom));
+ var convertExpr = Expression.Convert(paramExpr, typeof(T));
+
+ return Expression.Lambda<Func<TFrom, T>>(convertExpr, paramExpr).Compile();
+ }
+ }
+ }
+}
\ No newline at end of file