//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.EntityClient;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Xml.Linq;
namespace SchoolSample.EntityModel
{
public partial class SchoolEntities : ObjectContext
{
public const string ConnectionString = "name=SchoolEntities";
public const string ContainerName = "SchoolEntities";
#region Constructors
public SchoolEntities()
: base(ConnectionString, ContainerName)
{
Initialize();
}
public SchoolEntities(string connectionString)
: base(connectionString, ContainerName)
{
Initialize();
}
public SchoolEntities(EntityConnection connection)
: base(connection, ContainerName)
{
Initialize();
}
private void Initialize()
{
// Creating proxies requires the use of the ProxyDataContractResolver and
// may allow lazy loading which can expand the loaded graph during serialization.
ContextOptions.ProxyCreationEnabled = false;
ObjectMaterialized += new ObjectMaterializedEventHandler(HandleObjectMaterialized);
}
private void HandleObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{
var entity = e.Entity as IObjectWithChangeTracker;
if (entity != null)
{
bool changeTrackingEnabled = entity.ChangeTracker.ChangeTrackingEnabled;
try
{
entity.MarkAsUnchanged();
}
finally
{
entity.ChangeTracker.ChangeTrackingEnabled = changeTrackingEnabled;
}
this.StoreReferenceKeyValues(entity);
}
}
#endregion
#region ObjectSet Properties
public ObjectSet<Course> Courses
{
get { return _courses ?? (_courses = CreateObjectSet<Course>("Courses")); }
}
private ObjectSet<Course> _courses;
public ObjectSet<Enrollment> Enrollments
{
get { return _enrollments ?? (_enrollments = CreateObjectSet<Enrollment>("Enrollments")); }
}
private ObjectSet<Enrollment> _enrollments;
public ObjectSet<Person> People
{
get { return _people ?? (_people = CreateObjectSet<Person>("People")); }
}
private ObjectSet<Person> _people;
public ObjectSet<DefaultFilter> DefaultFilters
{
get { return _defaultFilters ?? (_defaultFilters = CreateObjectSet<DefaultFilter>("DefaultFilters")); }
}
private ObjectSet<DefaultFilter> _defaultFilters;
#endregion
}
public static class ObjectQueryExtension
{
/// <summary>
/// ApplyIncludePath takes the list of include paths from a CleintQuery object
/// and calls Include() on the ObjectQuery.
/// </summary>
/// <typeparam name="TEntity">Expected type of the ObjectQuery</typeparam>
/// <param name="source">The ObjectQuery to which the list of include paths will be applied</param>
/// <param name="clientQuery">The ClientQuery object that contains the list of include paths</param>
/// <returns></returns>
public static ObjectQuery<TEntity> ApplyIncludePath<TEntity>(this ObjectQuery<TEntity> source,
ClientQuery clientQuery) where TEntity : class
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (clientQuery == null)
{
throw new ArgumentNullException("clientQuery");
}
return clientQuery.IncludeList.Aggregate(source, (current, includeItem) => current.Include(includeItem));
}
/// <summary>
/// ApplyClientQuery takes both the list of include paths and deserialized Expression tree
/// from a CleintQuery object and applies on the ObjectQuery.
/// </summary>
/// <typeparam name="TEntity">Expected type of the ObjectQuery</typeparam>
/// <param name="source">The ObjectQuery to which both the list of include paths and deserialized Expression tree will be applied</param>
/// <param name="clientQuery">The ClientQuery object that contains both the list of include paths and deserialized Expression tree</param>
/// <param name="assemblies">Additional assemblies where types will be searched</param>
public static IQueryable<TEntity> ApplyClientQuery<TEntity>(this ObjectQuery<TEntity> source,
ClientQuery clientQuery,
IEnumerable<Assembly> assemblies = null)
where TEntity : class
{
return new DeserializableQuery<TEntity>(source.ApplyIncludePath(clientQuery), clientQuery, assemblies);
}
}
internal class DeserializableQuery<T> : IOrderedQueryable<T>
{
#region Private Data Member
private IQueryable<T> _innerQuery;
private DeserializableQueryProvider<T> _provider;
private ClientQuery _clientQuery;
private IEnumerable<Assembly> _assemblies;
#endregion Private Data Member
#region Public Property
public IQueryable<T> InnerQuery
{
get { return _innerQuery; }
}
public ClientQuery ClientQuery
{
get { return _clientQuery; }
}
public IEnumerable<Assembly> Assemblies
{
get { return _assemblies; }
}
#endregion Public Property
#region Constructor
public DeserializableQuery(IQueryable<T> innerQuery)
{
_innerQuery = innerQuery;
_provider = new DeserializableQueryProvider<T>(this);
_clientQuery = null;
_assemblies = null;
}
public DeserializableQuery(IQueryable<T> innerQuery, ClientQuery clientQuery, IEnumerable<Assembly> assemblies)
{
_innerQuery = innerQuery;
_provider = new DeserializableQueryProvider<T>(this);
_clientQuery = clientQuery;
_assemblies = assemblies;
}
#endregion Constructor
#region Interface Implementation
Expression IQueryable.Expression
{
get
{
if (_clientQuery != null)
{
return new Deserializer(_innerQuery.Expression, _assemblies)
.Deserialize(_clientQuery.XmlExpression);
}
return _innerQuery.Expression;
}
}
Type IQueryable.ElementType
{
get { return typeof (T); }
}
IQueryProvider IQueryable.Provider
{
get { return _provider; }
}
public IEnumerator<T> GetEnumerator()
{
if (_clientQuery != null)
{
return ((IQueryProvider) _provider).CreateQuery<T>(((IQueryable) this).Expression).GetEnumerator();
}
return _innerQuery.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
if (_clientQuery != null)
{
return ((IQueryProvider) _provider).CreateQuery(((IQueryable) this).Expression).GetEnumerator();
}
return ((IEnumerable) _innerQuery).GetEnumerator();
}
public override string ToString()
{
return _innerQuery.ToString();
}
#endregion Interface Implementation
}
internal class DeserializableQueryProvider<T> : IQueryProvider
{
#region Private Data Member
private DeserializableQuery<T> _query;
#endregion Private Data Member
#region Constructor
internal DeserializableQueryProvider(DeserializableQuery<T> query)
{
_query = query;
}
#endregion Constructor
#region Interface Implementation
IQueryable<TElement> IQueryProvider.CreateQuery<TElement>(Expression expression)
{
return new DeserializableQuery<TElement>(_query.InnerQuery.Provider.CreateQuery<TElement>(expression));
}
IQueryable IQueryProvider.CreateQuery(Expression expression)
{
return
(IQueryable)
Activator.CreateInstance(
typeof (DeserializableQuery<>).MakeGenericType(((IQueryable) _query).ElementType),
new object[] {expression});
}
TResult IQueryProvider.Execute<TResult>(Expression expression)
{
return _query.InnerQuery.Provider.Execute<TResult>(expression);
}
object IQueryProvider.Execute(Expression expression)
{
return _query.InnerQuery.Provider.Execute(expression);
}
#endregion Interface Implementation
}
internal class Deserializer
{
#region Private Data Member
private readonly Dictionary<string, ParameterExpression> _parameters =
new Dictionary<string, ParameterExpression>();
private readonly Expression _substituteExpression;
private readonly TypeResolver _resolver;
#endregion Private Data Member
#region Constructor
public Deserializer(Expression substituteExpression, IEnumerable<Assembly> assemblies = null)
{
_substituteExpression = substituteExpression;
_resolver = new TypeResolver(assemblies);
}
#endregion Constructor
#region Public Deserializer Method
public Expression Deserialize(XElement xml)
{
_parameters.Clear();
return ParseExpressionFromXmlNonNull(xml);
}
#endregion Public Deserializer Method
#region Private Deserializer Method
private Expression ParseExpressionFromXmlNonNull(XElement xml)
{
if (xml.Name.LocalName == "ClientQuery" && xml.Attribute("elementType") != null)
{
var elementTypeVisitor = new ElementTypeVisitor();
elementTypeVisitor.Visit(_substituteExpression);
if (elementTypeVisitor.ElementType == Type.GetType(xml.Attribute("elementType").Value))
{
return _substituteExpression;
}
else
{
throw new ArgumentException("Invalid ClientQuery element type.");
}
}
switch (xml.Name.LocalName)
{
case "BinaryExpression":
return ParseBinaryExpressionFromXml(xml);
case "ConditionalExpression":
return ParseConditionalExpressionFromXml(xml);
case "ConstantExpression":
return ParseConstantExpressionFromXml(xml);
case "InvocationExpression":
return ParseInvocationExpressionFromXml(xml);
case "LambdaExpression":
return ParseLambdaExpressionFromXml(xml);
case "ListInitExpression":
return ParseListInitExpressionFromXml(xml);
case "MemberExpression":
return ParseMemberExpressionFromXml(xml);
case "MemberInitExpression":
return ParseMemberInitExpressionFromXml(xml);
case "MethodCallExpression":
return ParseMethodCallExpressionFromXml(xml);
case "NewArrayExpression":
return ParseNewArrayExpressionFromXml(xml);
case "NewExpression":
return ParseNewExpressionFromXml(xml);
case "ParameterExpression":
return ParseParameterExpressionFromXml(xml);
case "TypeBinaryExpression":
return ParseTypeBinaryExpressionFromXml(xml);
case "UnaryExpression":
return ParseUnaryExpressionFromXml(xml);
default:
throw new NotSupportedException(xml.Name.LocalName);
}
}
/// <summary>
/// Parse BinaryExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private BinaryExpression ParseBinaryExpressionFromXml(XElement xml)
{
var right = ParseExpressionFromXml(xml.Element("Right"));
var left = ParseExpressionFromXml(xml.Element("Left"));
var method = ParseMethodInfoFromXml(xml.Element("Method"));
var conversion = ParseExpressionFromXml(xml.Element("Conversion")) as LambdaExpression;
var isLiftedToNull = ParseWithDataContractSerializer<bool>(xml.Element("IsLiftedToNull"));
var expressionType = ParseWithDataContractSerializer<ExpressionType>(xml.Element("NodeType"));
return Expression.MakeBinary(expressionType, left, right, isLiftedToNull, method, conversion);
}
/// <summary>
/// Parse ConditionalExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private ConditionalExpression ParseConditionalExpressionFromXml(XElement xml)
{
var test = ParseExpressionFromXml(xml.Element("Test"));
var ifTrue = ParseExpressionFromXml(xml.Element("IfTrue"));
var ifFalse = ParseExpressionFromXml(xml.Element("IfFalse"));
var type = ParseTypeFromXml(xml.Element("Type"));
return Expression.Condition(test, ifTrue, ifFalse, type);
}
/// <summary>
/// Parse ConstantExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private ConstantExpression ParseConstantExpressionFromXml(XElement xml)
{
var type = ParseTypeFromXml(xml.Element("Type"));
var result = ParseWithDataContractSerializer(xml.Element("Value"), type);
return Expression.Constant(result, type);
}
/// <summary>
/// Parse InvocationExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private InvocationExpression ParseInvocationExpressionFromXml(XElement xml)
{
var expression = ParseExpressionFromXml(xml.Element("Expression"));
var arguments = ParseExpressionListFromXml<Expression>(xml, "Arguments");
return Expression.Invoke(expression, arguments);
}
/// <summary>
/// Parse LambdaExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private LambdaExpression ParseLambdaExpressionFromXml(XElement xml)
{
var type = ParseTypeFromXml(xml.Element("Type"));
var body = ParseExpressionFromXml(xml.Element("Body"));
var name = ParseWithDataContractSerializer<string>(xml.Element("Name"));
var tailCall = ParseWithDataContractSerializer<bool>(xml.Element("TailCall"));
var parameters = ParseExpressionListFromXml<ParameterExpression>(xml, "Parameters");
return Expression.Lambda(type, body, name, tailCall, parameters);
}
/// <summary>
/// Parse ListInitExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private ListInitExpression ParseListInitExpressionFromXml(XElement xml)
{
var newExpression = ParseExpressionFromXml(xml.Element("NewExpression")) as NewExpression;
if (newExpression == null) throw new Exception("Expceted a NewExpression");
var initializers = ParseElementInitListFromXml(xml, "Initializers");
return Expression.ListInit(newExpression, initializers);
}
/// <summary>
/// Parse MemberExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private MemberExpression ParseMemberExpressionFromXml(XElement xml)
{
var expression = ParseExpressionFromXml(xml.Element("Expression"));
var member = ParseMemberInfoFromXml(xml.Element("Member"));
return Expression.MakeMemberAccess(expression, member);
}
/// <summary>
/// Parse MemberInitExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private MemberInitExpression ParseMemberInitExpressionFromXml(XElement xml)
{
var newExpression = ParseExpressionFromXml(xml.Element("NewExpression")) as NewExpression;
if (newExpression == null) throw new Exception("Expceted a NewExpression");
var bindings = ParseMemberBindingListFromXml(xml, "Bindings");
if (bindings == null) throw new Exception("Bindings cannot be null");
return Expression.MemberInit(newExpression, bindings);
}
/// <summary>
/// Parse MethodCallExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private MethodCallExpression ParseMethodCallExpressionFromXml(XElement xml)
{
var instance = ParseExpressionFromXml(xml.Element("Object"));
var method = ParseMethodInfoFromXml(xml.Element("Method"));
var arguments = ParseExpressionListFromXml<Expression>(xml, "Arguments") ?? new Expression[0];
return Expression.Call(instance, method, arguments);
}
/// <summary>
/// Parse NewArrayExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private NewArrayExpression ParseNewArrayExpressionFromXml(XElement xml)
{
var type = ParseTypeFromXml(xml.Element("Type"));
if (type == null) throw new Exception("Type cannot be null");
if (!type.IsArray) throw new Exception("Expected array type");
var elemType = type.GetElementType();
var expressions = ParseExpressionListFromXml<Expression>(xml, "Expressions");
var expressionType = ParseWithDataContractSerializer<ExpressionType>(xml.Element("NodeType"));
switch (expressionType)
{
case ExpressionType.NewArrayInit:
return Expression.NewArrayInit(elemType, expressions);
case ExpressionType.NewArrayBounds:
return Expression.NewArrayBounds(elemType, expressions);
default:
throw new Exception("Expected NewArrayInit or NewArrayBounds");
}
}
/// <summary>
/// Parse NewExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private NewExpression ParseNewExpressionFromXml(XElement xml)
{
var constructor = ParseConstructorInfoFromXml(xml.Element("Constructor"));
var arguments = ParseExpressionListFromXml<Expression>(xml, "Arguments").ToArray();
var members = ParseMemberInfoListFromXml<MemberInfo>(xml, "Members").ToArray();
return members.Length == 0
? Expression.New(constructor, arguments)
: Expression.New(constructor, arguments, members);
}
/// <summary>
/// Parse ParameterExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private ParameterExpression ParseParameterExpressionFromXml(XElement xml)
{
var type = ParseTypeFromXml(xml.Element("Type"));
var name = ParseWithDataContractSerializer<string>(xml.Element("Name"));
var id = name + type.FullName;
if (!_parameters.ContainsKey(id))
_parameters.Add(id, Expression.Parameter(type, name));
return _parameters[id];
}
/// <summary>
/// Parse TypeBinaryExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private TypeBinaryExpression ParseTypeBinaryExpressionFromXml(XElement xml)
{
var expression = ParseExpressionFromXml(xml.Element("Expression"));
var typeOperand = ParseTypeFromXml(xml.Element("TypeOperand"));
var expressionType = ParseWithDataContractSerializer<ExpressionType>(xml.Element("NodeType"));
switch (expressionType)
{
case ExpressionType.TypeEqual:
return Expression.TypeEqual(expression, typeOperand);
case ExpressionType.TypeIs:
return Expression.TypeIs(expression, typeOperand);
default:
throw new Exception("Expected TypeEqual or TypeIs");
}
}
/// <summary>
/// Parse UnaryExpression From XElement
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
private UnaryExpression ParseUnaryExpressionFromXml(XElement xml)
{
var operand = ParseExpressionFromXml(xml.Element("Operand"));
var type = ParseTypeFromXml(xml.Element("Type"));
var method = ParseMethodInfoFromXml(xml.Element("Method"));
var expressionType = ParseWithDataContractSerializer<ExpressionType>(xml.Element("NodeType"));
return Expression.MakeUnary(expressionType, operand, type, method);
}
#endregion Private Deserializer Method
#region Private Deserializer Helper Method
private ConstructorInfo ParseConstructorInfoFromXml(XElement xml)
{
if (xml.IsEmpty) return null;
var declaringType = ParseTypeFromXml(xml.Element("DeclaringType"));
var xElement = xml.Element("Parameters");
if (xElement == null) throw new Exception("Parameters not found.");
var parameters = from paramXml in xElement.Elements()
select ParseTypeFromXml(paramXml);
return declaringType.GetConstructor(parameters.ToArray());
}
private ElementInit ParseElementInitFromXml(XElement xml)
{
var addMethod = ParseMethodInfoFromXml(xml.Element("AddMethod"));
var arguments = ParseExpressionListFromXml<Expression>(xml, "Arguments");
return Expression.ElementInit(addMethod, arguments);
}
private Expression ParseExpressionFromXml(XElement xml)
{
return xml.IsEmpty ? null : ParseExpressionFromXmlNonNull(xml.Elements().First());
}
private FieldInfo ParseFieldInfoFromXml(XElement xml)
{
var xAttribute = xml.Attribute("FieldName");
if (xAttribute == null) throw new Exception("FieldName not found.");
var fieldName = xAttribute.Value;
var declaringType = ParseTypeFromXml(xml.Element("DeclaringType"));
return declaringType.GetField(fieldName);
}
private MemberBinding ParseMemberBindingFromXml(XElement xml)
{
var member = ParseMemberInfoFromXml(xml.Element("Member"));
switch (xml.Name.LocalName)
{
case "MemberAssignment":
var expression = ParseExpressionFromXml(xml.Element("Expression"));
return Expression.Bind(member, expression);
case "MemberMemberBinding":
var bindings = ParseMemberBindingListFromXml(xml, "Bindings");
return Expression.MemberBind(member, bindings);
case "MemberListBinding":
var initializers = ParseElementInitListFromXml(xml, "Initializers");
return Expression.ListBind(member, initializers);
}
throw new NotImplementedException();
}
private MemberInfo ParseMemberInfoFromXml(XElement xml)
{
var xAttribute = xml.Attribute("MemberType");
if (xAttribute == null) throw new Exception("MemberType not found.");
var memberType = (MemberTypes) Enum.Parse(typeof (MemberTypes), xAttribute.Value, false);
switch (memberType)
{
case MemberTypes.Field:
return ParseFieldInfoFromXml(xml);
case MemberTypes.Property:
return ParsePropertyInfoFromXml(xml);
case MemberTypes.Method:
return ParseMethodInfoFromXml(xml);
case MemberTypes.Constructor:
return ParseConstructorInfoFromXml(xml);
default:
throw new NotSupportedException(string.Format("MEmberType {0} not supported", memberType));
}
}
private MethodInfo ParseMethodInfoFromXml(XElement xml)
{
if (xml.IsEmpty) return null;
var xAttribute = xml.Attribute("MethodName");
if (xAttribute == null) throw new Exception("MethodName not found.");
var name = xAttribute.Value;
var declaringType = ParseTypeFromXml(xml.Element("DeclaringType"));
var xElement = xml.Element("Parameters");
if (xElement == null) throw new Exception("Parameters not found.");
var parameters = from paramXml in xElement.Elements()
select ParseTypeFromXml(paramXml);
xElement = xml.Element("GenericArgTypes");
if (xElement == null) throw new Exception("GenericArgTypes not found.");
var genArgs = from argXml in xElement.Elements()
select ParseTypeFromXml(argXml);
return _resolver.GetMethod(declaringType, name, parameters.ToArray(), genArgs.ToArray());
}
private PropertyInfo ParsePropertyInfoFromXml(XElement xml)
{
var xAttribute = xml.Attribute("PropertyName");
if (xAttribute == null) throw new Exception("PropertyName not found.");
var propertyName = xAttribute.Value;
var declaringType = ParseTypeFromXml(xml.Element("DeclaringType"));
return declaringType.GetProperty(propertyName);
}
private Type ParseTypeFromXml(XElement xml)
{
return ParseTypeFromXmlCore(xml.Elements().First());
}
private IEnumerable<ElementInit> ParseElementInitListFromXml(XElement xml, string elemName)
{
var xElement = xml.Element(elemName);
if (xElement == null) throw new Exception(elemName + " not found.");
return from tXml in xElement.Elements()
select ParseElementInitFromXml(tXml);
}
private IEnumerable<T> ParseExpressionListFromXml<T>(XElement xml, string elemName) where T : Expression
{
var xElement = xml.Element(elemName);
if (xElement == null) throw new Exception(elemName + " not found.");
return from tXml in xElement.Elements()
select (T) ParseExpressionFromXmlNonNull(tXml);
}
private IEnumerable<MemberBinding> ParseMemberBindingListFromXml(XElement xml, string elemName)
{
var xElement = xml.Element(elemName);
if (xElement == null) throw new Exception(elemName + " not found.");
return from tXml in xElement.Elements()
select ParseMemberBindingFromXml(tXml);
}
private IEnumerable<T> ParseMemberInfoListFromXml<T>(XElement xml, string elemName) where T : MemberInfo
{
var xElement = xml.Element(elemName);
if (xElement == null) throw new Exception(elemName + " not found.");
return from tXml in xElement.Elements()
select (T) ParseMemberInfoFromXml(tXml);
}
private Type ParseTypeFromXmlCore(XElement xml)
{
switch (xml.Name.ToString())
{
case "Type":
return ParseNormalTypeFromXmlCore(xml);
case "AnonymousType":
return ParseAnonymousTypeFromXmlCore(xml);
default:
throw new ArgumentException("Expected 'Type' or 'AnonymousType'");
}
}
private Type ParseNormalTypeFromXmlCore(XElement xml)
{
if (!xml.HasElements)
{
var xAttribute = xml.Attribute("Name");
if (xAttribute == null) throw new Exception("Name not found.");
return _resolver.GetType(xAttribute.Value);
}
var genericArgumentTypes = from genArgXml in xml.Elements()
select ParseTypeFromXmlCore(genArgXml);
var attribute = xml.Attribute("Name");
if (attribute == null) throw new Exception("Name not found.");
return _resolver.GetType(attribute.Value, genericArgumentTypes);
}
private Type ParseAnonymousTypeFromXmlCore(XElement xElement)
{
var xAttribute = xElement.Attribute("Name");
if (xAttribute == null) throw new Exception("Name not found.");
var name = xAttribute.Value;
var properties = from propXml in xElement.Elements("Property")
let attribute = propXml.Attribute("Name")
where attribute != null
select new TypeResolver.NameTypePair
{
Name = attribute.Value,
Type = ParseTypeFromXml(propXml)
};
var ctrParams = from propXml in xElement.Elements("Constructor").Elements("Parameter")
let attribute = propXml.Attribute("Name")
where attribute != null
select new TypeResolver.NameTypePair
{
Name = attribute.Value,
Type = ParseTypeFromXml(propXml)
};
return _resolver.GetOrCreateAnonymousType(name, properties.ToArray(), ctrParams.ToArray());
}
private T ParseWithDataContractSerializer<T>(XElement xml)
{
if (xml == null) throw new Exception("XElement cannot be null.");
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml.Value)))
{
var deserializer = new DataContractSerializer(typeof (T));
return (T) deserializer.ReadObject(stream);
}
}
private object ParseWithDataContractSerializer(XElement xml, Type expectedType)
{
if (xml == null) throw new Exception("XElement cannot be null.");
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml.Value)))
{
var deserializer = new DataContractSerializer(expectedType);
return deserializer.ReadObject(stream);
}
}
#endregion Private Deserializer Helper Method
}
internal class ElementTypeVisitor : ExpressionVisitor
{
public Type ElementType { get; private set; }
protected override Expression VisitConstant(ConstantExpression e)
{
if (typeof (IOrderedQueryable).IsAssignableFrom(e.Type))
{
var elementType = ((IOrderedQueryable) e.Value).ElementType;
if (typeof (IOrderedQueryable<>).MakeGenericType(new[] {elementType}).IsAssignableFrom(e.Type))
{
ElementType = elementType;
}
}
return base.VisitConstant(e);
}
}
internal sealed class TypeResolver
{
#region Private Data Member
private readonly Dictionary<AnonTypeId, Type> _anonymousTypes = new Dictionary<AnonTypeId, Type>();
private readonly ModuleBuilder _moduleBuilder;
private int _anonymousTypeIndex;
private readonly HashSet<Assembly> _assemblies = new HashSet<Assembly>
{
typeof (String).Assembly,
// mscorlib.dll
typeof (ExpressionType).Assembly,
// System.Core.dll
typeof (XElement).Assembly,
// System.Xml.Linq.dll
Assembly.GetExecutingAssembly(),
};
#endregion Private Data Member
#region Constructor
public TypeResolver(IEnumerable<Assembly> assemblies = null)
{
var asmname = new AssemblyName {Name = "AnonymousTypes"};
var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(asmname,
AssemblyBuilderAccess.Run);
_moduleBuilder = assemblyBuilder.DefineDynamicModule("AnonymousTypes");
if (assemblies != null)
{
foreach (var assembly in assemblies)
_assemblies.Add(assembly);
}
}
#endregion Constructor
#region Public Method
/// <summary>
/// Get type of a generic type
/// </summary>
/// <param name="typeName"></param>
/// <param name="genericArgumentTypes"></param>
/// <returns></returns>
public Type GetType(string typeName, IEnumerable<Type> genericArgumentTypes)
{
return GetType(typeName).MakeGenericType(genericArgumentTypes.ToArray());
}
/// <summary>
/// Get type based on type name
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public Type GetType(string typeName)
{
Type type;
if (string.IsNullOrEmpty(typeName))
throw new ArgumentNullException("typeName");
// array type
if (typeName.EndsWith("[]"))
return GetType(typeName.Substring(0, typeName.Length - 2)).MakeArrayType();
// load type from assemblies
foreach (var assembly in _assemblies)
{
type = assembly.GetType(typeName);
if (type != null)
return type;
}
// call Type.GetType()
type = Type.GetType(typeName, false, true);
if (type != null)
return type;
throw new ArgumentException("Could not find a matching type", typeName);
}
/// <summary>
/// Get method based on type, name and parameters
/// </summary>
/// <param name="declaringType"></param>
/// <param name="name"></param>
/// <param name="parameterTypes"></param>
/// <param name="genArgTypes"></param>
/// <returns></returns>
public MethodInfo GetMethod(Type declaringType, string name, Type[] parameterTypes, Type[] genArgTypes)
{
var methods = from mi in declaringType.GetMethods()
where mi.Name == name
select mi;
foreach (var method in methods)
{
try
{
var realMethod = method;
if (method.IsGenericMethod)
{
realMethod = method.MakeGenericMethod(genArgTypes);
}
var methodParameterTypes = realMethod.GetParameters().Select(p => p.ParameterType);
if (MatchPiecewise(parameterTypes, methodParameterTypes))
{
return realMethod;
}
}
catch (ArgumentException)
{
}
}
return null;
}
/// <summary>
/// Get or create anonymous type
/// </summary>
/// <param name="name"></param>
/// <param name="properties"></param>
/// <param name="ctrParams"></param>
/// <returns></returns>
public Type GetOrCreateAnonymousType(string name, NameTypePair[] properties, NameTypePair[] ctrParams)
{
var id = new AnonTypeId(name, properties.Concat(ctrParams));
if (_anonymousTypes.ContainsKey(id))
return _anonymousTypes[id];
const string anonPrefix = "<>f__AnonymousType";
var anonTypeBuilder = _moduleBuilder.DefineType(anonPrefix + _anonymousTypeIndex++,
TypeAttributes.Public | TypeAttributes.Class);
var fieldBuilders = new FieldBuilder[properties.Length];
var propertyBuilders = new PropertyBuilder[properties.Length];
for (var i = 0; i < properties.Length; i++)
{
fieldBuilders[i] = anonTypeBuilder.DefineField("_generatedfield_" + properties[i].Name,
properties[i].Type, FieldAttributes.Private);
propertyBuilders[i] = anonTypeBuilder.DefineProperty(properties[i].Name,
System.Reflection.PropertyAttributes.None,
properties[i].Type, new Type[0]);
var propertyGetterBuilder = anonTypeBuilder.DefineMethod("get_" + properties[i].Name,
MethodAttributes.Public,
properties[i].Type, new Type[0]);
var getIlGenerator = propertyGetterBuilder.GetILGenerator();
getIlGenerator.Emit(OpCodes.Ldarg_0);
getIlGenerator.Emit(OpCodes.Ldfld, fieldBuilders[i]);
getIlGenerator.Emit(OpCodes.Ret);
propertyBuilders[i].SetGetMethod(propertyGetterBuilder);
}
var constructorBuilder = anonTypeBuilder.DefineConstructor(
MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Public,
CallingConventions.Standard, ctrParams.Select(prop => prop.Type).ToArray());
var constructorIlGenerator = constructorBuilder.GetILGenerator();
for (var i = 0; i < ctrParams.Length; i++)
{
constructorIlGenerator.Emit(OpCodes.Ldarg_0);
constructorIlGenerator.Emit(OpCodes.Ldarg, i + 1);
constructorIlGenerator.Emit(OpCodes.Stfld, fieldBuilders[i]);
constructorBuilder.DefineParameter(i + 1, ParameterAttributes.None, ctrParams[i].Name);
}
constructorIlGenerator.Emit(OpCodes.Ret);
var anonType = anonTypeBuilder.CreateType();
_anonymousTypes.Add(id, anonType);
return anonType;
}
#endregion Public Method
#region Private Method
private bool MatchPiecewise<T>(IEnumerable<T> first, IEnumerable<T> second)
{
var firstArray = first.ToArray();
var secondArray = second.ToArray();
if (firstArray.Length != secondArray.Length)
return false;
return !firstArray.Where((t, i) => !t.Equals(secondArray[i])).Any();
}
#endregion Private Method
#region Nested Classes
public class NameTypePair
{
public string Name { get; set; }
public Type Type { get; set; }
public override int GetHashCode()
{
return Name.GetHashCode() + Type.GetHashCode();
}
public override bool Equals(object obj)
{
if (!(obj is NameTypePair))
return false;
var other = obj as NameTypePair;
return Name.Equals(other.Name) && Type.Equals(other.Type);
}
}
private class AnonTypeId
{
public string Name { get; private set; }
public IEnumerable<NameTypePair> Properties { get; private set; }
public AnonTypeId(string name, IEnumerable<NameTypePair> properties)
{
Name = name;
Properties = properties;
}
public override int GetHashCode()
{
return Name.GetHashCode() + Properties.Sum(ntpair => ntpair.GetHashCode());
}
public override bool Equals(object obj)
{
if (!(obj is AnonTypeId))
return false;
var other = obj as AnonTypeId;
return (Name.Equals(other.Name)
&& Properties.SequenceEqual(other.Properties));
}
}
#endregion Nested Classes
}
}