Skip to content

Commit 5bcabe7

Browse files
committed
Getting getter method of indexer property improved
+ small QueryHelper improvements
1 parent 5c25e73 commit 5bcabe7

5 files changed

Lines changed: 36 additions & 17 deletions

File tree

Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,7 @@ private Expression MaterializeThroughOwner(Expression target, Expression tuple,
483483
var materializedOwner = MaterializeThroughOwner((Expression) owner, tuple, defaultIfEmpty);
484484
Expression fieldExpression;
485485
if (field.Field.IsDynamicallyDefined) {
486-
var attributes = materializedOwner.Type.GetCustomAttributes(WellKnownTypes.DefaultMemberAttribute, true);
487-
var indexerPropertyName = ((DefaultMemberAttribute) attributes.Single()).MemberName;
488-
var methodInfo = materializedOwner.Type.GetProperty(indexerPropertyName).GetGetMethod();
486+
var methodInfo = materializedOwner.Type.GetProperty(Reflection.WellKnown.IndexerPropertyName).GetGetMethod();
489487
fieldExpression = Expression.Convert(Expression.Call(materializedOwner, methodInfo, Expression.Constant(field.Field.Name)), field.Field.ValueType);
490488
}
491489
else

Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ internal static class QueryHelper
2525
{
2626
private sealed class OwnerWrapper<TOwner>
2727
{
28+
public static readonly Type GenericDef = typeof(OwnerWrapper<>);
29+
2830
public TOwner Owner { get; set; }
2931

3032
public OwnerWrapper(TOwner owner)
@@ -76,22 +78,29 @@ public static bool IsDirectEntitySetQuery(Expression entitySet)
7678
return false;
7779
var wrapper = ((MemberExpression) owner).Expression;
7880
return wrapper.NodeType==ExpressionType.Constant
79-
&& wrapper.Type.IsGenericType
80-
&& wrapper.Type.GetGenericTypeDefinition()==typeof (OwnerWrapper<>);
81+
&& wrapper.Type.IsOwnerWrapper();
8182
}
8283

8384
public static Expression CreateDirectEntitySetQuery(EntitySetBase entitySet)
8485
{
8586
// A hack making expression to look like regular parameter
8687
// (ParameterExtractor.IsParameter => true)
8788
var owner = entitySet.Owner;
89+
var ownerType = owner.TypeInfo.UnderlyingType;
8890
var wrapper = Activator.CreateInstance(
89-
typeof (OwnerWrapper<>).MakeGenericType(owner.GetType()), owner);
90-
var wrappedOwner = Expression.Property(Expression.Constant(wrapper), "Owner");
91+
OwnerWrapper<int>.GenericDef.MakeGenericType(ownerType), owner);
92+
var wrappedOwner = Expression.Property(Expression.Constant(wrapper), nameof(OwnerWrapper<int>.Owner));
9193
if (!entitySet.Field.IsDynamicallyDefined) {
9294
return Expression.Property(wrappedOwner, entitySet.Field.UnderlyingProperty);
9395
}
94-
var indexers = owner.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
96+
//fast way to get indexer getter method
97+
var indexerGetter = ownerType.GetMethod(Reflection.WellKnown.IndexerPropertyGetterName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
98+
if (indexerGetter.Attributes.HasFlag(MethodAttributes.SpecialName)
99+
&& (indexerGetter.DeclaringType == WellKnownOrmTypes.Persistent || indexerGetter.DeclaringType == WellKnownOrmTypes.Entity))
100+
return Expression.Convert(Expression.Call(Expression.Constant(owner), indexerGetter, new[] { Expression.Constant(entitySet.Field.Name) }), entitySet.Field.ValueType);
101+
102+
// old-fashion slow way, if something went wrong
103+
var indexers = ownerType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
95104
.Where(p => p.GetIndexParameters().Any())
96105
.Select(p => p.GetGetMethod());
97106
return Expression.Convert(Expression.Call(Expression.Constant(owner),indexers.Single(), new []{Expression.Constant(entitySet.Field.Name)}), entitySet.Field.ValueType);
@@ -191,7 +200,7 @@ public static void TryAddConvarianceCast(ref Expression source, Type baseType)
191200
public static Type GetSequenceElementType(Type type)
192201
{
193202
var sequenceType = type.GetGenericInterface(WellKnownInterfaces.EnumerableOfT);
194-
return sequenceType!=null ? sequenceType.GetGenericArguments()[0] : null;
203+
return sequenceType?.GetGenericArguments()[0];
195204
}
196205

197206
private static Expression BuildExpressionForFieldRecursivly(FieldInfo field, Expression parameter)
@@ -202,5 +211,9 @@ private static Expression BuildExpressionForFieldRecursivly(FieldInfo field, Exp
202211
}
203212
return Expression.Property(parameter, field.DeclaringField.UnderlyingProperty);
204213
}
214+
215+
private static bool IsOwnerWrapper(this Type type) =>
216+
(type.MetadataToken ^ OwnerWrapper<int>.GenericDef.MetadataToken) == 0
217+
&& ReferenceEquals(type.Module, OwnerWrapper<int>.GenericDef.Module);
205218
}
206219
}

Orm/Xtensive.Orm/Orm/Linq/Rewriters/PersistentIndexerRewriter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ private Expression GetMemberExpression(MethodCallExpression mc)
7878
if (propertyInfo!=null)
7979
return Expression.MakeMemberAccess(mc.Object, propertyInfo);
8080

81-
var attributes = mc.Object.Type.GetCustomAttributes(WellKnownTypes.DefaultMemberAttribute, true);
82-
var indexerPropertyName = ((DefaultMemberAttribute)attributes.Single()).MemberName;
83-
var indexerProperty = mc.Object.Type.GetProperty(indexerPropertyName);
81+
//var attributes = mc.Object.Type.GetCustomAttributes(WellKnownTypes.DefaultMemberAttribute, true);
82+
//var indexerPropertyName = ((DefaultMemberAttribute)attributes.Single()).MemberName;
83+
var indexerProperty = mc.Object.Type.GetProperty(Reflection.WellKnown.IndexerPropertyName);
8484
if (indexerProperty!=null)
8585
return Expression.MakeIndex(mc.Object, indexerProperty, new[] {Expression.Constant(name)});
8686
throw new InvalidOperationException(String.Format(Strings.ExFieldXNotFoundInTypeX, name, mc.Object.Type));
@@ -96,7 +96,7 @@ private bool IsIndexerAccessor(Expression expression)
9696
return false;
9797
}
9898
var method = methodCallExpression.Method;
99-
return method.Name == "get_Item"
99+
return method.Name == Reflection.WellKnown.IndexerPropertyGetterName
100100
&& method.DeclaringType switch { var declaringType => declaringType == WellKnownOrmTypes.Persistent || declaringType == WellKnownOrmInterfaces.Entity }
101101
&& context.Evaluator.CanBeEvaluated(methodCallExpression.Arguments[0]);
102102
}

Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,12 @@ private Expression VisitIndex(IndexExpression ie)
983983
}
984984
}
985985
var fieldInfo = typeInfo.Fields[evaluatedArgument];
986-
return Expression.Convert(Expression.Call(objectExpression, objectExpression.Type.GetProperty("Item").GetGetMethod(), new[] {Expression.Constant(evaluatedArgument)}), fieldInfo.ValueType);
986+
return Expression.Convert(
987+
Expression.Call(
988+
objectExpression,
989+
objectExpression.Type.GetProperty(Reflection.WellKnown.IndexerPropertyName).GetGetMethod(),
990+
new[] {Expression.Constant(evaluatedArgument)}),
991+
fieldInfo.ValueType);
987992
}
988993

989994
private static bool IsConditionalOrWellknown(Expression expression)
@@ -1054,9 +1059,7 @@ private IList<Expression> GetStructureFields(
10541059
propertyAccessorExpression = Expression.MakeMemberAccess(Expression.Convert(expression, structureType), fieldExpression.UnderlyingProperty);
10551060
}
10561061
else {
1057-
var attributes = structureType.GetCustomAttributes(WellKnownTypes.DefaultMemberAttribute, true);
1058-
var indexerPropertyName = ((DefaultMemberAttribute)attributes.Single()).MemberName;
1059-
var methodInfo = structureType.GetProperty(indexerPropertyName).GetGetMethod();
1062+
var methodInfo = structureType.GetProperty(Reflection.WellKnown.IndexerPropertyName).GetGetMethod();
10601063
propertyAccessorExpression = Expression.Call(Expression.Convert(expression, structureType), methodInfo, Expression.Constant(fieldExpression.Name));
10611064
}
10621065
var memberExpression = (Expression) Expression.Condition(

Orm/Xtensive.Orm/Reflection/WellKnown.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public static partial class WellKnown
3838
/// </summary>
3939
public const string IndexerPropertyName = "Item";
4040

41+
/// <summary>
42+
/// Returns "get_Item"
43+
/// </summary>
44+
public const string IndexerPropertyGetterName = "get_Item";
45+
4146
/// <summary>
4247
/// Returns "add_".
4348
/// </summary>

0 commit comments

Comments
 (0)