// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.TypeSystem { /// /// Anonymous type. /// public class AnonymousType : AbstractType { ICompilation compilation; IUnresolvedProperty[] unresolvedProperties; IList resolvedProperties; public AnonymousType(ICompilation compilation, IList properties) { if (compilation == null) throw new ArgumentNullException("compilation"); if (properties == null) throw new ArgumentNullException("properties"); this.compilation = compilation; this.unresolvedProperties = properties.ToArray(); var context = new SimpleTypeResolveContext(compilation.MainAssembly); this.resolvedProperties = new ProjectedList(context, unresolvedProperties, (c, p) => new AnonymousTypeProperty(p, c, this)); } sealed class AnonymousTypeProperty : DefaultResolvedProperty { readonly AnonymousType declaringType; public AnonymousTypeProperty(IUnresolvedProperty unresolved, ITypeResolveContext parentContext, AnonymousType declaringType) : base(unresolved, parentContext) { this.declaringType = declaringType; } public override IType DeclaringType { get { return declaringType; } } public override bool Equals(object obj) { AnonymousTypeProperty p = obj as AnonymousTypeProperty; return p != null && this.Name == p.Name && declaringType.Equals(p.declaringType); } public override int GetHashCode() { return declaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode()); } protected override IMethod CreateResolvedAccessor(IUnresolvedMethod unresolvedAccessor) { return new AnonymousTypeAccessor(unresolvedAccessor, context, this); } } sealed class AnonymousTypeAccessor : DefaultResolvedMethod { readonly AnonymousTypeProperty owner; public AnonymousTypeAccessor(IUnresolvedMethod unresolved, ITypeResolveContext parentContext, AnonymousTypeProperty owner) : base(unresolved, parentContext, isExtensionMethod: false) { this.owner = owner; } public override IMember AccessorOwner { get { return owner; } } public override IType DeclaringType { get { return owner.DeclaringType; } } public override bool Equals(object obj) { AnonymousTypeAccessor p = obj as AnonymousTypeAccessor; return p != null && this.Name == p.Name && owner.DeclaringType.Equals(p.owner.DeclaringType); } public override int GetHashCode() { return owner.DeclaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode()); } } public override ITypeReference ToTypeReference() { return new AnonymousTypeReference(unresolvedProperties); } public override string Name { get { return "Anonymous Type"; } } public override TypeKind Kind { get { return TypeKind.Anonymous; } } public override IEnumerable DirectBaseTypes { get { yield return compilation.FindType(KnownTypeCode.Object); } } public override bool? IsReferenceType { get { return true; } } public IList Properties { get { return resolvedProperties; } } public override IEnumerable GetMethods(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) return EmptyList.Instance; else return compilation.FindType(KnownTypeCode.Object).GetMethods(filter, options); } public override IEnumerable GetMethods(IList typeArguments, Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { if ((options & GetMemberOptions.IgnoreInheritedMembers) == GetMemberOptions.IgnoreInheritedMembers) return EmptyList.Instance; else return compilation.FindType(KnownTypeCode.Object).GetMethods(typeArguments, filter, options); } public override IEnumerable GetProperties(Predicate filter = null, GetMemberOptions options = GetMemberOptions.None) { for (int i = 0; i < unresolvedProperties.Length; i++) { if (filter == null || filter(unresolvedProperties[i])) yield return resolvedProperties[i]; } } public override IEnumerable GetAccessors(Predicate filter, GetMemberOptions options) { for (int i = 0; i < unresolvedProperties.Length; i++) { if (unresolvedProperties[i].CanGet) { if (filter == null || filter(unresolvedProperties[i].Getter)) yield return resolvedProperties[i].Getter; } if (unresolvedProperties[i].CanSet) { if (filter == null || filter(unresolvedProperties[i].Setter)) yield return resolvedProperties[i].Setter; } } } public override int GetHashCode() { unchecked { int hashCode = resolvedProperties.Count; foreach (var p in resolvedProperties) { hashCode *= 31; hashCode += p.Name.GetHashCode() ^ p.ReturnType.GetHashCode(); } return hashCode; } } public override bool Equals(IType other) { AnonymousType o = other as AnonymousType; if (o == null || resolvedProperties.Count != o.resolvedProperties.Count) return false; for (int i = 0; i < resolvedProperties.Count; i++) { IProperty p1 = resolvedProperties[i]; IProperty p2 = o.resolvedProperties[i]; if (p1.Name != p2.Name || !p1.ReturnType.Equals(p2.ReturnType)) return false; } return true; } } /// /// Anonymous type reference. /// [Serializable] public class AnonymousTypeReference : ITypeReference { readonly IUnresolvedProperty[] unresolvedProperties; public AnonymousTypeReference(IUnresolvedProperty[] properties) { if (properties == null) throw new ArgumentNullException("properties"); this.unresolvedProperties = properties; } public IType Resolve(ITypeResolveContext context) { return new AnonymousType(context.Compilation, unresolvedProperties); } } }