Skip to content

Commit 81f5a43

Browse files
jehhynesOlegKarasik
authored andcommitted
Fix ParseNew to be compatible with NHibernate.Linq... (#18)
* ClassFactory and ParseNew uses a constructor (This is consistent with .NET compiler-generated code for anonymous types; and is required for compatibility with NHibernate.Linq) * DefaultDynamicLinqCustomTypeProvider skips assemblies which throw ReflectionTypeLoadException * Slightly optimized "GenerateConstructor" method. Replaced Type[0] with Type.Empty types, Type.GetType("System.Object") with typeof(object). Updated code formatting to accomodate project styles. * Replaced two LINQ selects with single for loop (optimized pass time & memory usage). Replaced "var" with "explicit types" to accomodate project style. * Improved comments. Added a way to check if assemlby is dynamic for .NET Framework 3.5. Replaced new Type[0] with Type.EmptyTypes.
1 parent fd37d9f commit 81f5a43

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

Src/System.Linq.Dynamic/ClassFactory.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,28 @@ private ClassFactory()
9393
#endif
9494
}
9595

96+
private static void GenerateConstructor(TypeBuilder tb, FieldInfo[] fields)
97+
{
98+
ConstructorInfo objCtor = typeof(object).GetConstructor(Type.EmptyTypes);
99+
ConstructorBuilder cb = tb.DefineConstructor(
100+
MethodAttributes.Public,
101+
CallingConventions.Standard,
102+
fields.Select(x => x.FieldType).ToArray());
103+
104+
ILGenerator gen = cb.GetILGenerator();
105+
gen.Emit(OpCodes.Ldarg_0);
106+
gen.Emit(OpCodes.Call, objCtor);
107+
for (int i = 0; i < fields.Length; i++)
108+
{
109+
var f = fields[i];
110+
111+
gen.Emit(OpCodes.Ldarg_0);
112+
gen.Emit(OpCodes.Ldarg, i + 1);
113+
gen.Emit(OpCodes.Stfld, f);
114+
}
115+
gen.Emit(OpCodes.Ret);
116+
}
117+
96118
private static FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
97119
{
98120
FieldInfo[] fields = new FieldBuilder[properties.Length];
@@ -208,6 +230,7 @@ private Type CreateDynamicClass(Signature signature)
208230
TypeAttributes.Class | TypeAttributes.Public,
209231
typeof(DynamicClass));
210232
FieldInfo[] fields = GenerateProperties(tb, signature.properties);
233+
GenerateConstructor(tb, fields);
211234
GenerateEquals(tb, fields);
212235
GenerateGetHashCode(tb, fields);
213236

Src/System.Linq.Dynamic/DynamicLinqTypeProvider.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System.Collections.Generic;
2+
using System.Reflection;
3+
using System.Reflection.Emit;
24

35
namespace System.Linq.Dynamic
46
{
@@ -10,7 +12,7 @@ namespace System.Linq.Dynamic
1012
public sealed class DynamicLinqTypeAttribute : Attribute { }
1113

1214
/// <summary>
13-
/// The default <see cref="IDynamicLinkCustomTypeProvider"/>. Scans the current <see cref="AppDomain"/> for all types marked with
15+
/// The default <see cref="IDynamicLinkCustomTypeProvider"/>. Scans the current <see cref="AppDomain"/> for all exported types marked with
1416
/// <see cref="DynamicLinqTypeAttribute"/>, and adds them as custom Dynamic Link types.
1517
/// </summary>
1618
public class DefaultDynamicLinqCustomTypeProvider : IDynamicLinkCustomTypeProvider
@@ -22,8 +24,24 @@ private static IEnumerable<Type> FindTypesMarkedWithAttribute()
2224
return AppDomain.CurrentDomain.GetAssemblies()
2325
#if !NET35
2426
.Where(x => !x.IsDynamic)
27+
#else
28+
// Prior to .NET Framework 4.0 there were no "IsDynamic" property.
29+
// Thanks to reflection we know that for dynamic assemblies generated via reflection emit
30+
// "ManifestModule.ScopeName" is set to "RefEmit_InMemoryManifestModule"
31+
.Where(x => x.ManifestModule.ScopeName != "RefEmit_InMemoryManifestModule")
2532
#endif
26-
.SelectMany(x => x.GetTypes())
33+
.SelectMany(x =>
34+
{
35+
try
36+
{
37+
return x.GetTypes();
38+
}
39+
catch (ReflectionTypeLoadException)
40+
{
41+
// Some referenced assemblies may throw a ReflectionTypeLoadException. In this case, just eat the exception.
42+
return Type.EmptyTypes;
43+
}
44+
})
2745
.Where(x => x.GetCustomAttributes(typeof(DynamicLinqTypeAttribute), false).Any());
2846
}
2947

Src/System.Linq.Dynamic/ExpressionParser.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,10 +1040,16 @@ Expression ParseNew()
10401040
ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
10411041
NextToken();
10421042
Type type = ClassFactory.Instance.GetDynamicClass(properties);
1043-
MemberBinding[] bindings = new MemberBinding[properties.Count];
1044-
for (int i = 0; i < bindings.Length; i++)
1045-
bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
1046-
return Expression.MemberInit(Expression.New(type), bindings);
1043+
PropertyInfo[] members = new PropertyInfo[properties.Count];
1044+
Type[] ctorArgTypes = new Type[properties.Count];
1045+
for (int i = 0; i < properties.Count; ++i)
1046+
{
1047+
DynamicProperty dp = properties[i];
1048+
1049+
members[i] = type.GetProperty(dp.Name);
1050+
ctorArgTypes[i] = dp.Type;
1051+
}
1052+
return Expression.New(type.GetConstructor(ctorArgTypes), expressions, members);
10471053
}
10481054

10491055
Expression ParseLambdaInvocation(LambdaExpression lambda)

0 commit comments

Comments
 (0)