Repository: ignite Updated Branches: refs/heads/master 99842bf19 -> 3e3b91a8a
http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs index cd3becf..737c7c4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySurrogateTypeDescriptor.cs @@ -1,4 +1,4 @@ -/* +/* * 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. @@ -62,19 +62,6 @@ namespace Apache.Ignite.Core.Impl.Binary _name = typeName; } - /// <summary> - /// Constructor. - /// </summary> - /// <param name="cfg">Configuration.</param> - /// <param name="name">Type name.</param> - public BinarySurrogateTypeDescriptor(BinaryConfiguration cfg, string name) - { - _cfg = cfg; - _name = name; - - _id = BinaryUtils.TypeId(name, cfg.NameMapper, cfg.IdMapper); - } - /** <inheritDoc /> */ public Type Type { http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs index ca2c9ae..0979ea5 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -22,9 +22,7 @@ namespace Apache.Ignite.Core.Impl.Binary using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; - using System.Globalization; using System.IO; - using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; @@ -1638,34 +1636,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /** - * <summary>Convert type name.</summary> - * <param name="typeName">Type name.</param> - * <param name="converter">Converter.</param> - * <returns>Converted name.</returns> - */ - public static string ConvertTypeName(string typeName, IBinaryNameMapper converter) - { - var typeName0 = typeName; - - try - { - if (converter != null) - typeName = converter.GetTypeName(typeName); - } - catch (Exception e) - { - throw new BinaryObjectException("Failed to convert type name due to converter exception " + - "[typeName=" + typeName + ", converter=" + converter + ']', e); - } - - if (typeName == null) - throw new BinaryObjectException("Name converter returned null name for type [typeName=" + - typeName0 + ", converter=" + converter + "]"); - - return typeName; - } - - /** * <summary>Convert field name.</summary> * <param name="fieldName">Field name.</param> * <param name="converter">Converter.</param> @@ -1693,67 +1663,13 @@ namespace Apache.Ignite.Core.Impl.Binary return fieldName; } - /** - * <summary>Extract simple type name.</summary> - * <param name="typeName">Type name.</param> - * <returns>Simple type name.</returns> - */ - public static string SimpleTypeName(string typeName) - { - int idx = typeName.LastIndexOf('.'); - - return idx < 0 ? typeName : typeName.Substring(idx + 1); - } - - /** - * <summary>Resolve type ID.</summary> - * <param name="typeName">Type name.</param> - * <param name="nameMapper">Name mapper.</param> - * <param name="idMapper">ID mapper.</param> - */ - public static int TypeId(string typeName, IBinaryNameMapper nameMapper, - IBinaryIdMapper idMapper) - { - Debug.Assert(typeName != null); - - typeName = ConvertTypeName(typeName, nameMapper); - - int id = 0; - - if (idMapper != null) - { - try - { - id = idMapper.GetTypeId(typeName); - } - catch (Exception e) - { - throw new BinaryObjectException("Failed to resolve type ID due to ID mapper exception " + - "[typeName=" + typeName + ", idMapper=" + idMapper + ']', e); - } - } - - if (id == 0) - id = GetStringHashCode(typeName); - - return id; - } - /// <summary> - /// Gets the name of the type. + /// Gets the SQL name of the type. /// </summary> - /// <param name="type">The type.</param> - /// <returns> - /// Simple type name for non-generic types; simple type name with appended generic arguments for generic types. - /// </returns> - public static string GetTypeName(Type type) + public static string GetSqlTypeName(Type type) { - if (!type.IsGenericType) - return type.Name; - - var args = type.GetGenericArguments().Select(GetTypeName).Aggregate((x, y) => x + "," + y); - - return string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", type.Name, args); + // SQL always uses simple type name without namespace, parent class, etc. + return type.FullName; } /** @@ -1796,31 +1712,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Compare contents of two byte array chunks. - /// </summary> - /// <param name="arr1">Array 1.</param> - /// <param name="offset1">Offset 1.</param> - /// <param name="len1">Length 1.</param> - /// <param name="arr2">Array 2.</param> - /// <param name="offset2">Offset 2.</param> - /// <param name="len2">Length 2.</param> - /// <returns>True if array chunks are equal.</returns> - public static bool CompareArrays(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2, int len2) - { - if (len1 == len2) - { - for (int i = 0; i < len1; i++) - { - if (arr1[offset1 + i] != arr2[offset2 + i]) - return false; - } - - return true; - } - return false; - } - - /// <summary> /// Writes invocation result. /// </summary> /// <param name="writer">Writer.</param> http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs index b60ced9..4707ce2 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -407,7 +407,8 @@ namespace Apache.Ignite.Core.Impl.Binary return _typeNameToDesc.TryGetValue(typeName, out desc) ? (IBinaryTypeDescriptor) desc - : new BinarySurrogateTypeDescriptor(_cfg, typeName); + : new BinarySurrogateTypeDescriptor(_cfg, + GetTypeId(typeName, _cfg.IdMapper), typeName); } /// <summary> @@ -444,7 +445,7 @@ namespace Apache.Ignite.Core.Impl.Binary var type = _ignite == null ? null : _ignite.BinaryProcessor.GetType(typeId); if (type != null) - return AddUserType(type, typeId, BinaryUtils.GetTypeName(type), true, desc); + return AddUserType(type, typeId, GetTypeName(type), true, desc); } var meta = GetBinaryType(typeId); @@ -471,8 +472,8 @@ namespace Apache.Ignite.Core.Impl.Binary { Debug.Assert(type != null); - var typeName = BinaryUtils.GetTypeName(type); - var typeId = BinaryUtils.TypeId(typeName, _cfg.NameMapper, _cfg.IdMapper); + var typeName = GetTypeName(type); + var typeId = GetTypeId(typeName, _cfg.IdMapper); var registered = _ignite != null && _ignite.BinaryProcessor.RegisterType(typeId, type); @@ -538,7 +539,7 @@ namespace Apache.Ignite.Core.Impl.Binary private void AddUserType(BinaryConfiguration cfg, BinaryTypeConfiguration typeCfg, TypeResolver typeResolver) { // Get converter/mapper/serializer. - IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? _cfg.NameMapper; + IBinaryNameMapper nameMapper = typeCfg.NameMapper ?? _cfg.NameMapper ?? GetDefaultNameMapper(); IBinaryIdMapper idMapper = typeCfg.IdMapper ?? _cfg.IdMapper; @@ -561,8 +562,8 @@ namespace Apache.Ignite.Core.Impl.Binary } // Type is found. - var typeName = BinaryUtils.GetTypeName(type); - int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); + var typeName = GetTypeName(type, nameMapper); + int typeId = GetTypeId(typeName, idMapper); var affKeyFld = typeCfg.AffinityKeyFieldName ?? GetAffinityKeyFieldNameFromAttribute(type); var serializer = GetSerializer(cfg, typeCfg, type, typeId, nameMapper, idMapper, _log); @@ -572,9 +573,9 @@ namespace Apache.Ignite.Core.Impl.Binary else { // Type is not found. - string typeName = BinaryUtils.SimpleTypeName(typeCfg.TypeName); + string typeName = GetTypeName(typeCfg.TypeName, nameMapper); - int typeId = BinaryUtils.TypeId(typeName, nameMapper, idMapper); + int typeId = GetTypeId(typeName, idMapper); AddType(null, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, null, typeCfg.AffinityKeyFieldName, typeCfg.IsEnum); @@ -689,11 +690,15 @@ namespace Apache.Ignite.Core.Impl.Binary serializer = serializer ?? new BinarySystemTypeSerializer<T>(ctor); + // System types always use simple name mapper. + var typeName = type.Name; + if (typeId == 0) - typeId = BinaryUtils.TypeId(type.Name, null, null); + { + typeId = BinaryUtils.GetStringHashCode(typeName); + } - AddType(type, typeId, BinaryUtils.GetTypeName(type), false, false, null, null, serializer, affKeyFldName, - false); + AddType(type, typeId, typeName, false, false, null, null, serializer, affKeyFldName, false); } /// <summary> @@ -756,5 +761,71 @@ namespace Apache.Ignite.Core.Impl.Binary type.AssemblyQualifiedName); } } + + /// <summary> + /// Gets the name of the type. + /// </summary> + private string GetTypeName(Type type, IBinaryNameMapper mapper = null) + { + return GetTypeName(type.AssemblyQualifiedName, mapper); + } + + /// <summary> + /// Gets the name of the type. + /// </summary> + private string GetTypeName(string fullTypeName, IBinaryNameMapper mapper = null) + { + mapper = mapper ?? _cfg.NameMapper ?? GetDefaultNameMapper(); + + var typeName = mapper.GetTypeName(fullTypeName); + + if (typeName == null) + { + throw new BinaryObjectException("IBinaryNameMapper returned null name for type [typeName=" + + fullTypeName + ", mapper=" + mapper + "]"); + } + + return typeName; + } + + /// <summary> + /// Resolve type ID. + /// </summary> + /// <param name="typeName">Type name.</param> + /// <param name="idMapper">ID mapper.</param> + private static int GetTypeId(string typeName, IBinaryIdMapper idMapper) + { + Debug.Assert(typeName != null); + + int id = 0; + + if (idMapper != null) + { + try + { + id = idMapper.GetTypeId(typeName); + } + catch (Exception e) + { + throw new BinaryObjectException("Failed to resolve type ID due to ID mapper exception " + + "[typeName=" + typeName + ", idMapper=" + idMapper + ']', e); + } + } + + if (id == 0) + { + id = BinaryUtils.GetStringHashCode(typeName); + } + + return id; + } + + /// <summary> + /// Gets the default name mapper. + /// </summary> + private static IBinaryNameMapper GetDefaultNameMapper() + { + return BinaryBasicNameMapper.FullNameInstance; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs new file mode 100644 index 0000000..527d47c --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeNameParser.cs @@ -0,0 +1,384 @@ +/* + * 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.Binary +{ + using System.Collections.Generic; + using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Impl.Common; + + /// <summary> + /// Parses .NET-style type names and deconstructs them into parts. + /// </summary> + internal class TypeNameParser + { + /** */ + private readonly int _start; + + /** */ + private readonly string _typeName; + + /** */ + private int _pos; + + /// <summary> + /// Initializes a new instance of the <see cref="TypeNameParser" /> class. + /// </summary> + private TypeNameParser(string typeName, ref int pos) + { + _typeName = typeName; + _start = pos; + _pos = _start; + + NameEnd = -1; + NameStart = 0; + AssemblyStart = -1; + AssemblyEnd = -1; + ArrayStart = -1; + + Parse(); + + pos = _pos; + } + + /// <summary> + /// Parses the specified type name. + /// </summary> + public static TypeNameParser Parse(string typeName) + { + IgniteArgumentCheck.NotNullOrEmpty(typeName, "typeName"); + + int pos = 0; + + return new TypeNameParser(typeName, ref pos); + } + + /// <summary> + /// Gets the name start. + /// </summary> + public int NameStart { get; private set; } + + /// <summary> + /// Gets the name end. + /// </summary> + public int NameEnd { get; private set; } + + /// <summary> + /// Gets the start of the assembly name. + /// </summary> + public int AssemblyStart { get; private set; } + + /// <summary> + /// Gets the start of the assembly name. + /// </summary> + public int AssemblyEnd { get; private set; } + + /// <summary> + /// Gets the start of the array definition. + /// </summary> + public int ArrayStart { get; private set; } + + /// <summary> + /// Gets the start of the array definition. + /// </summary> + public int ArrayEnd { get; private set; } + + /// <summary> + /// Gets the generics. + /// </summary> + public ICollection<TypeNameParser> Generics { get; private set; } + + /// <summary> + /// Gets the type name (without namespace). + /// </summary> + public string GetName() + { + if (NameEnd < 0) + return null; + + return _typeName.Substring(NameStart, NameEnd - NameStart + 1); + } + + /// <summary> + /// Gets the full type name (with namespace). + /// </summary> + public string GetFullName() + { + if (NameEnd < 0) + return null; + + return _typeName.Substring(_start, NameEnd - _start + 1); + } + + /// <summary> + /// Gets the array part. + /// </summary> + public string GetArray() + { + if (ArrayStart < 0) + return null; + + return _typeName.Substring(ArrayStart, ArrayEnd - ArrayStart + 1); + } + + /// <summary> + /// Gets assembly name part. + /// </summary> + public string GetAssemblyName() + { + if (AssemblyStart < 0) + return null; + + return _typeName.Substring(AssemblyStart, AssemblyEnd - AssemblyStart + 1); + } + + /// <summary> + /// Parses this instance. + /// </summary> + private void Parse() + { + // Example: + // System.Collections.Generic.List`1[[System.Int32[], mscorlib, Version=4.0.0.0, Culture=neutral, + // PublicKeyToken =b77a5c561934e089]][], mscorlib, Version=4.0.0.0, Culture=neutral, + // PublicKeyToken =b77a5c561934e089 + + // 1) Namespace+name, ends with '`' or '[' or ',' + // 2) Generic, starts with '`' + // 3) Array, starts with '[' + // 4) Assembly, starts with ',', ends with EOL or `]` + + ParseTypeName(); + ParseGeneric(); + ParseArrayDefinition(); + ParseAssemblyName(); + } + + /// <summary> + /// Parses the type name with namespace. + /// </summary> + private void ParseTypeName() + { + NameStart = _pos; + + while (Shift()) + { + if (Char == '.' || Char == '+') + { + NameStart = _pos + 1; + } + + if (Char == '`') + { + // Non-null ist indicates detected generic type. + Generics = Generics ?? new List<TypeNameParser>(); + } + + if (Char == '[' || Char == ']' || Char == ',' || Char == ' ') + break; + } + + NameEnd = End ? _pos : _pos - 1; + } + + /// <summary> + /// Parses the generic part. + /// </summary> + private void ParseGeneric() + { + // Generics can be nested: + // UserQuery+Gen`1+Gen2`1[[System.Int32, mscorlib],[System.String, mscorlib]] + + if (Generics == null) + { + return; + } + + if (Char != '[') + { + throw new IgniteException("Invalid generic type name, number must be followed by '[': " + _typeName); + } + + while (true) + { + RequireShift(); + + if (Char != '[') + { + throw new IgniteException("Invalid generic type name, '[' must be followed by '[': " + _typeName); + } + + RequireShift(); + + Generics.Add(new TypeNameParser(_typeName, ref _pos)); + + if (Char != ']') + { + throw new IgniteException("Invalid generic type name, no matching ']': " + _typeName); + } + + RequireShift(); + + if (Char == ']') + { + Shift(); + return; + } + + if (Char != ',') + { + throw new IgniteException("Invalid generic type name, expected ',': " + _typeName); + } + } + } + + /// <summary> + /// Parses the array definition. + /// </summary> + private void ParseArrayDefinition() + { + if (Char != '[') + return; + + ArrayStart = _pos; + + var bracket = true; + + RequireShift(); + + while (true) + { + if (Char == '[') + { + if (bracket) + { + throw new IgniteException("Invalid array specification: " + _typeName); + } + + bracket = true; + } + else if (Char == ']') + { + if (!bracket) + { + throw new IgniteException("Invalid array specification: " + _typeName); + } + + bracket = false; + } + else if (Char == ',') + { + if (!bracket) + break; + } + else + { + if (bracket) + { + throw new IgniteException("Invalid array specification: " + _typeName); + } + + break; + } + + if (!Shift()) + break; + } + + ArrayEnd = Char == ']' ? _pos : _pos - 1; + } + + /// <summary> + /// Parses assembly name part. + /// </summary> + private void ParseAssemblyName() + { + if (Char != ',') + return; + + RequireShift(); + + SkipSpaces(); + + AssemblyStart = _pos; + + while (Char != ']' && Shift()) + { + // No-op. + } + + AssemblyEnd = End ? _pos : _pos - 1; + } + + /// <summary> + /// Shifts the position forward. + /// </summary> + private bool Shift() + { + if (_pos < _typeName.Length - 1) + { + _pos++; + return true; + } + + return false; + } + + /// <summary> + /// Requires position shift or throws an error. + /// </summary> + private void RequireShift() + { + if (!Shift()) + { + throw new IgniteException("Invalid type name - not enough data: " + _typeName); + } + } + + /// <summary> + /// Skips the spaces. + /// </summary> + private void SkipSpaces() + { + while (Char == ' ' && Shift()) + { + // No-op. + } + } + + /// <summary> + /// Gets a value indicating whether we are at the end of the string. + /// </summary> + private bool End + { + get { return _pos >= _typeName.Length - 1; } + } + + /// <summary> + /// Gets the current character. + /// </summary> + private char Char + { + get { return _typeName[_pos]; } + } + + /** <inheritdoc /> */ + public override string ToString() + { + return _typeName; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs index 36dde4b..68222d4 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/TypeResolver.cs @@ -21,20 +21,14 @@ namespace Apache.Ignite.Core.Impl.Binary using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; - using System.Globalization; using System.Linq; using System.Reflection; - using System.Text.RegularExpressions; /// <summary> /// Resolves types by name. /// </summary> internal class TypeResolver { - /** Regex to parse generic types from binary configuration. Allows nested generics in type arguments. */ - private static readonly Regex GenericTypeRegex = - new Regex(@"([^`,\[\]]*)(?:`[0-9]+)?(?:\[((?:(?<br>\[)|(?<-br>\])|[^\[\]]*)+)\])?", RegexOptions.Compiled); - /** Assemblies loaded in ReflectionOnly mode. */ private readonly Dictionary<string, Assembly> _reflectionOnlyAssemblies = new Dictionary<string, Assembly>(); @@ -54,11 +48,15 @@ namespace Apache.Ignite.Core.Impl.Binary var type = Type.GetType(typeName, false); if (type != null) + { return type; + } + + var parsedType = TypeNameParser.Parse(typeName); // Partial names should be resolved by scanning assemblies. - return ResolveType(assemblyName, typeName, AppDomain.CurrentDomain.GetAssemblies()) - ?? ResolveTypeInReferencedAssemblies(assemblyName, typeName); + return ResolveType(assemblyName, parsedType, AppDomain.CurrentDomain.GetAssemblies()) + ?? ResolveTypeInReferencedAssemblies(assemblyName, parsedType); } /// <summary> @@ -70,10 +68,23 @@ namespace Apache.Ignite.Core.Impl.Binary /// <returns> /// Resolved type. /// </returns> - private static Type ResolveType(string assemblyName, string typeName, ICollection<Assembly> assemblies) + private static Type ResolveType(string assemblyName, TypeNameParser typeName, ICollection<Assembly> assemblies) { - return ResolveGenericType(assemblyName, typeName, assemblies) ?? - ResolveNonGenericType(assemblyName, typeName, assemblies); + var type = ResolveNonGenericType(assemblyName, typeName.GetFullName(), assemblies); + + if (type == null) + { + return null; + } + + if (type.IsGenericTypeDefinition && typeName.Generics != null) + { + var genArgs = typeName.Generics.Select(x => ResolveType(assemblyName, x, assemblies)).ToArray(); + + return type.MakeGenericType(genArgs); + } + + return type; } /// <summary> @@ -85,64 +96,34 @@ namespace Apache.Ignite.Core.Impl.Binary /// <returns>Resolved type, or null.</returns> private static Type ResolveNonGenericType(string assemblyName, string typeName, ICollection<Assembly> assemblies) { + // Fully-qualified name can be resolved with system mechanism. + var type = Type.GetType(typeName, false); + + if (type != null) + { + return type; + } + if (!string.IsNullOrEmpty(assemblyName)) + { assemblies = assemblies .Where(x => x.FullName == assemblyName || x.GetName().Name == assemblyName).ToArray(); + } if (!assemblies.Any()) + { return null; + } // Trim assembly qualification var commaIdx = typeName.IndexOf(','); if (commaIdx > 0) + { typeName = typeName.Substring(0, commaIdx); + } - return assemblies.Select(a => a.GetType(typeName, false, false)).FirstOrDefault(type => type != null); - } - - /// <summary> - /// Resolves the name of the generic type by resolving each generic arg separately - /// and substituting it's fully qualified name. - /// (Assembly.GetType finds generic types only when arguments are fully qualified). - /// </summary> - /// <param name="assemblyName">Name of the assembly.</param> - /// <param name="typeName">Name of the type.</param> - /// <param name="assemblies">Assemblies</param> - /// <returns>Fully qualified generic type name, or null if argument(s) could not be resolved.</returns> - private static Type ResolveGenericType(string assemblyName, string typeName, ICollection<Assembly> assemblies) - { - var match = GenericTypeRegex.Match(typeName); - - if (!match.Success || !match.Groups[2].Success) - return null; - - // Try to construct generic type; each generic arg can also be a generic type. - var genericArgs = GenericTypeRegex.Matches(match.Groups[2].Value) - .OfType<Match>().Select(m => m.Value).Where(v => !string.IsNullOrWhiteSpace(v)) - .Select(v => ResolveType(null, TrimBrackets(v), assemblies)).ToArray(); - - if (genericArgs.Any(x => x == null)) - return null; - - var genericType = ResolveNonGenericType(assemblyName, - string.Format(CultureInfo.InvariantCulture, "{0}`{1}", match.Groups[1].Value, genericArgs.Length), - assemblies); - - if (genericType == null) - return null; - - return genericType.MakeGenericType(genericArgs); - } - - /// <summary> - /// Trims the brackets from generic type arg. - /// </summary> - private static string TrimBrackets(string s) - { - return s.StartsWith("[", StringComparison.Ordinal) && s.EndsWith("]", StringComparison.Ordinal) - ? s.Substring(1, s.Length - 2) - : s; + return assemblies.Select(a => a.GetType(typeName, false, false)).FirstOrDefault(x => x != null); } /// <summary> @@ -153,7 +134,7 @@ namespace Apache.Ignite.Core.Impl.Binary /// <returns> /// Resolved type. /// </returns> - private Type ResolveTypeInReferencedAssemblies(string assemblyName, string typeName) + private Type ResolveTypeInReferencedAssemblies(string assemblyName, TypeNameParser typeName) { ResolveEventHandler resolver = (sender, args) => GetReflectionOnlyAssembly(args.Name); http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs index e909575..c665fe7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs @@ -168,7 +168,7 @@ namespace Apache.Ignite.Linq.Impl /// </summary> private void ValidateTableName() { - var validTableNames = GetValidTableNames(); + var validTableNames = GetValidTableNames().Select(x => EscapeTableName(x)).ToArray(); if (!validTableNames.Contains(_tableName, StringComparer.OrdinalIgnoreCase)) { @@ -201,7 +201,7 @@ namespace Apache.Ignite.Linq.Impl /// </summary> private static string GetTableName(QueryEntity e) { - return e.TableName ?? e.ValueTypeName.Split('.').Last(); + return e.TableName ?? e.ValueTypeName; } /// <summary> @@ -213,12 +213,16 @@ namespace Apache.Ignite.Linq.Impl var validTableNames = GetValidTableNames(); if (validTableNames.Length == 1) - return validTableNames[0]; + { + return EscapeTableName(validTableNames[0]); + } - var valueTypeName = cacheValueType.Name; + var valueTypeName = cacheValueType.FullName; if (validTableNames.Contains(valueTypeName, StringComparer.OrdinalIgnoreCase)) - return valueTypeName; + { + return EscapeTableName(valueTypeName); + } throw new CacheException(string.Format("Table name cannot be inferred for cache '{0}', " + "please use AsCacheQueryable overload with tableName parameter. " + @@ -227,6 +231,16 @@ namespace Apache.Ignite.Linq.Impl } /// <summary> + /// Escapes the name of the table: strips namespace and nested class qualifiers. + /// </summary> + private static string EscapeTableName(string valueTypeName) + { + var nsIndex = Math.Max(valueTypeName.LastIndexOf('.'), valueTypeName.LastIndexOf('+')); + + return nsIndex > 0 ? valueTypeName.Substring(nsIndex + 1) : valueTypeName; + } + + /// <summary> /// Gets the item type of closed generic i enumerable. /// </summary> private static Type GetItemTypeOfClosedGenericIEnumerable(Type enumerableType, string argumentName) http://git-wip-us.apache.org/repos/asf/ignite/blob/3e3b91a8/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs index 99712e3..3659158 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs @@ -338,8 +338,8 @@ namespace Apache.Ignite.Linq.Impl var entity = cacheCfg.QueryEntities.FirstOrDefault(e => e.Aliases != null && - (e.KeyType == keyValTypes[0] || e.KeyTypeName == keyValTypes[0].Name) && - (e.ValueType == keyValTypes[1] || e.ValueTypeName == keyValTypes[1].Name)); + (e.KeyType == keyValTypes[0] || e.KeyTypeName == keyValTypes[0].FullName) && + (e.ValueType == keyValTypes[1] || e.ValueTypeName == keyValTypes[1].FullName)); if (entity == null) return fieldName;
