Browse Source

Merge pull request #4113 from icsharpcode/remove-type-reference

Remove ITypeReference
pull/4115/head
Daniel Grunwald 1 week ago committed by GitHub
parent
commit
20714f9225
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 46
      ICSharpCode.Decompiler/TypeSystem/ArrayType.cs
  2. 38
      ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs
  3. 29
      ICSharpCode.Decompiler/TypeSystem/ITypeResolveContext.cs
  4. 104
      ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs
  5. 103
      ICSharpCode.Decompiler/TypeSystem/Implementation/TypeParameterReference.cs
  6. 9
      ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs
  7. 8
      ICSharpCode.Decompiler/TypeSystem/KnownTypeCode.cs
  8. 10
      ICSharpCode.Decompiler/TypeSystem/NullableType.cs
  9. 98
      ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs
  10. 38
      ICSharpCode.Decompiler/TypeSystem/PointerType.cs
  11. 13
      ICSharpCode.Decompiler/TypeSystem/SpecialType.cs
  12. 13
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs
  13. 118
      ICSharpCode.Decompiler/Util/ProjectedList.cs

46
ICSharpCode.Decompiler/TypeSystem/ArrayType.cs

@ -174,50 +174,4 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -174,50 +174,4 @@ namespace ICSharpCode.Decompiler.TypeSystem
return new ArrayType(compilation, e, dimensions, nullability);
}
}
[Serializable]
public sealed class ArrayTypeReference : ITypeReference, ISupportsInterning
{
readonly ITypeReference elementType;
readonly int dimensions;
public ArrayTypeReference(ITypeReference elementType, int dimensions = 1)
{
if (elementType == null)
throw new ArgumentNullException(nameof(elementType));
if (dimensions <= 0)
throw new ArgumentOutOfRangeException(nameof(dimensions), dimensions, "dimensions must be positive");
this.elementType = elementType;
this.dimensions = dimensions;
}
public ITypeReference ElementType {
get { return elementType; }
}
public int Dimensions {
get { return dimensions; }
}
public IType Resolve(ITypeResolveContext context)
{
return new ArrayType(context.Compilation, elementType.Resolve(context), dimensions);
}
public override string ToString()
{
return elementType.ToString() + "[" + new string(',', dimensions - 1) + "]";
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ dimensions;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ArrayTypeReference o = other as ArrayTypeReference;
return o != null && elementType == o.elementType && dimensions == o.dimensions;
}
}
}

38
ICSharpCode.Decompiler/TypeSystem/ByReferenceType.cs

@ -69,42 +69,4 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -69,42 +69,4 @@ namespace ICSharpCode.Decompiler.TypeSystem
return new ByReferenceType(e);
}
}
[Serializable]
public sealed class ByReferenceTypeReference : ITypeReference, ISupportsInterning
{
readonly ITypeReference elementType;
public ByReferenceTypeReference(ITypeReference elementType)
{
if (elementType == null)
throw new ArgumentNullException(nameof(elementType));
this.elementType = elementType;
}
public ITypeReference ElementType {
get { return elementType; }
}
public IType Resolve(ITypeResolveContext context)
{
return new ByReferenceType(elementType.Resolve(context));
}
public override string ToString()
{
return elementType.ToString() + "&";
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ 91725814;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ByReferenceTypeReference brt = other as ByReferenceTypeReference;
return brt != null && this.elementType == brt.elementType;
}
}
}

29
ICSharpCode.Decompiler/TypeSystem/ITypeReference.cs → ICSharpCode.Decompiler/TypeSystem/ITypeResolveContext.cs

@ -20,35 +20,6 @@ @@ -20,35 +20,6 @@
namespace ICSharpCode.Decompiler.TypeSystem
{
/// <summary>
/// Represents a reference to a type.
/// Must be resolved before it can be used as type.
/// </summary>
public interface ITypeReference
{
// Keep this interface simple: I decided against having GetMethods/GetEvents etc. here,
// so that the Resolve step is never hidden from the consumer.
// I decided against implementing IFreezable here: IUnresolvedTypeDefinition can be used as ITypeReference,
// but when freezing the reference, one wouldn't expect the definition to freeze.
/// <summary>
/// Resolves this type reference.
/// </summary>
/// <param name="context">
/// Context to use for resolving this type reference.
/// Which kind of context is required depends on the which kind of type reference this is;
/// please consult the documentation of the method that was used to create this type reference,
/// or that of the class implementing this method.
/// </param>
/// <returns>
/// Returns the resolved type.
/// In case of an error, returns an unknown type (<see cref="TypeKind.Unknown"/>).
/// Never returns null.
/// </returns>
IType Resolve(ITypeResolveContext context);
}
public interface ITypeResolveContext : ICompilationProvider
{
/// <summary>

104
ICSharpCode.Decompiler/TypeSystem/Implementation/NestedTypeReference.cs

@ -1,104 +0,0 @@ @@ -1,104 +0,0 @@
// 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;
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
/// <summary>
/// Type reference used to reference nested types.
/// </summary>
[Serializable]
public sealed class NestedTypeReference : ITypeReference, ISupportsInterning
{
readonly ITypeReference declaringTypeRef;
readonly string name;
readonly int additionalTypeParameterCount;
readonly bool? isReferenceType;
/// <summary>
/// Creates a new NestedTypeReference.
/// </summary>
/// <param name="declaringTypeRef">Reference to the declaring type.</param>
/// <param name="name">Name of the nested class</param>
/// <param name="additionalTypeParameterCount">Number of type parameters on the inner class (without type parameters on baseTypeRef)</param>
/// <remarks>
/// <paramref name="declaringTypeRef"/> must be exactly the (unbound) declaring type, not a derived type, not a parameterized type.
/// NestedTypeReference thus always resolves to a type definition, never to (partially) parameterized types.
/// </remarks>
public NestedTypeReference(ITypeReference declaringTypeRef, string name, int additionalTypeParameterCount, bool? isReferenceType = null)
{
if (declaringTypeRef == null)
throw new ArgumentNullException(nameof(declaringTypeRef));
if (name == null)
throw new ArgumentNullException(nameof(name));
this.declaringTypeRef = declaringTypeRef;
this.name = name;
this.additionalTypeParameterCount = additionalTypeParameterCount;
this.isReferenceType = isReferenceType;
}
public ITypeReference DeclaringTypeReference {
get { return declaringTypeRef; }
}
public string Name {
get { return name; }
}
public int AdditionalTypeParameterCount {
get { return additionalTypeParameterCount; }
}
public IType Resolve(ITypeResolveContext context)
{
ITypeDefinition declaringType = declaringTypeRef.Resolve(context) as ITypeDefinition;
if (declaringType != null)
{
int tpc = declaringType.TypeParameterCount;
foreach (IType type in declaringType.NestedTypes)
{
if (type.Name == name && type.TypeParameterCount == tpc + additionalTypeParameterCount)
return type;
}
}
return new UnknownType(null, name, additionalTypeParameterCount);
}
public override string ToString()
{
if (additionalTypeParameterCount == 0)
return declaringTypeRef + "+" + name;
else
return declaringTypeRef + "+" + name + "`" + additionalTypeParameterCount;
}
int ISupportsInterning.GetHashCodeForInterning()
{
return declaringTypeRef.GetHashCode() ^ name.GetHashCode() ^ additionalTypeParameterCount;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
NestedTypeReference o = other as NestedTypeReference;
return o != null && declaringTypeRef == o.declaringTypeRef && name == o.name
&& additionalTypeParameterCount == o.additionalTypeParameterCount
&& isReferenceType == o.isReferenceType;
}
}
}

103
ICSharpCode.Decompiler/TypeSystem/Implementation/TypeParameterReference.cs

@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
// 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.Globalization;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
[Serializable]
public sealed class TypeParameterReference : ITypeReference
{
static readonly TypeParameterReference[] classTypeParameterReferences = new TypeParameterReference[8];
static readonly TypeParameterReference[] methodTypeParameterReferences = new TypeParameterReference[8];
/// <summary>
/// Creates a type parameter reference.
/// For common type parameter references, this method may return a shared instance.
/// </summary>
public static TypeParameterReference Create(SymbolKind ownerType, int index)
{
if (index >= 0 && index < 8 && (ownerType == SymbolKind.TypeDefinition || ownerType == SymbolKind.Method))
{
TypeParameterReference[] arr = (ownerType == SymbolKind.TypeDefinition) ? classTypeParameterReferences : methodTypeParameterReferences;
TypeParameterReference result = LazyInit.VolatileRead(ref arr[index]);
if (result == null)
{
result = LazyInit.GetOrSet(ref arr[index], new TypeParameterReference(ownerType, index));
}
return result;
}
else
{
return new TypeParameterReference(ownerType, index);
}
}
readonly SymbolKind ownerType;
readonly int index;
public int Index {
get {
return index;
}
}
public TypeParameterReference(SymbolKind ownerType, int index)
{
this.ownerType = ownerType;
this.index = index;
}
public IType Resolve(ITypeResolveContext context)
{
if (ownerType == SymbolKind.Method)
{
IMethod method = context.CurrentMember as IMethod;
if (method != null && index < method.TypeParameters.Count)
{
return method.TypeParameters[index];
}
return DummyTypeParameter.GetMethodTypeParameter(index);
}
else if (ownerType == SymbolKind.TypeDefinition)
{
ITypeDefinition typeDef = context.CurrentTypeDefinition;
if (typeDef != null && index < typeDef.TypeParameters.Count)
{
return typeDef.TypeParameters[index];
}
return DummyTypeParameter.GetClassTypeParameter(index);
}
else
{
return SpecialType.UnknownType;
}
}
public override string ToString()
{
if (ownerType == SymbolKind.Method)
return "!!" + index.ToString(CultureInfo.InvariantCulture);
else
return "!" + index.ToString(CultureInfo.InvariantCulture);
}
}
}

9
ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -26,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
/// An unknown type where (part) of the name is known.
/// </summary>
[Serializable]
public class UnknownType : AbstractType, ITypeDefinitionOrUnknown, ITypeReference
public class UnknownType : AbstractType, ITypeDefinitionOrUnknown
{
readonly bool namespaceKnown;
readonly FullTypeName fullTypeName;
@ -71,13 +71,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -71,13 +71,6 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
get { return TypeKind.Unknown; }
}
IType ITypeReference.Resolve(ITypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
return this;
}
public override ITypeDefinitionOrUnknown GetDefinitionOrUnknown()
{
return this;

8
ICSharpCode.Decompiler/TypeSystem/KnownTypeReference.cs → ICSharpCode.Decompiler/TypeSystem/KnownTypeCode.cs

@ -168,8 +168,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -168,8 +168,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// <summary>
/// Contains well-known type references.
/// </summary>
[Serializable]
public sealed class KnownTypeReference : ITypeReference
public sealed class KnownTypeReference
{
internal const int KnownTypeCodeCount = (int)KnownTypeCode.RuntimeMethodHandle + 1;
@ -301,11 +300,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -301,11 +300,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
public TopLevelTypeName TypeName => new TopLevelTypeName(namespaceName, name, typeParameterCount);
public IType Resolve(ITypeResolveContext context)
{
return context.Compilation.FindType(knownTypeCode);
}
public override string ToString()
{
return GetCSharpNameByTypeCode(knownTypeCode) ?? (this.Namespace + "." + this.Name);

10
ICSharpCode.Decompiler/TypeSystem/NullableType.cs

@ -73,15 +73,5 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -73,15 +73,5 @@ namespace ICSharpCode.Decompiler.TypeSystem
else
return nullableType;
}
/// <summary>
/// Creates a nullable type reference.
/// </summary>
public static ParameterizedTypeReference Create(ITypeReference elementType)
{
if (elementType == null)
throw new ArgumentNullException(nameof(elementType));
return new ParameterizedTypeReference(KnownTypeReference.Get(KnownTypeCode.NullableOfT), new[] { elementType });
}
}
}

98
ICSharpCode.Decompiler/TypeSystem/ParameterizedType.cs

@ -358,102 +358,4 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -358,102 +358,4 @@ namespace ICSharpCode.Decompiler.TypeSystem
return new ParameterizedType(g, ta);
}
}
/// <summary>
/// ParameterizedTypeReference is a reference to generic class that specifies the type parameters.
/// Example: List&lt;string&gt;
/// </summary>
[Serializable]
public sealed class ParameterizedTypeReference : ITypeReference, ISupportsInterning
{
readonly ITypeReference genericType;
readonly ITypeReference[] typeArguments;
public ParameterizedTypeReference(ITypeReference genericType, IEnumerable<ITypeReference> typeArguments)
{
if (genericType == null)
throw new ArgumentNullException(nameof(genericType));
if (typeArguments == null)
throw new ArgumentNullException(nameof(typeArguments));
this.genericType = genericType;
this.typeArguments = typeArguments.ToArray();
for (int i = 0; i < this.typeArguments.Length; i++)
{
if (this.typeArguments[i] == null)
throw new ArgumentNullException("typeArguments[" + i + "]");
}
}
public ITypeReference GenericType {
get { return genericType; }
}
public IReadOnlyList<ITypeReference> TypeArguments {
get {
return typeArguments;
}
}
public IType Resolve(ITypeResolveContext context)
{
IType baseType = genericType.Resolve(context);
int tpc = baseType.TypeParameterCount;
if (tpc == 0)
return baseType;
IType[] resolvedTypes = new IType[tpc];
for (int i = 0; i < resolvedTypes.Length; i++)
{
if (i < typeArguments.Length)
resolvedTypes[i] = typeArguments[i].Resolve(context);
else
resolvedTypes[i] = SpecialType.UnknownType;
}
return new ParameterizedType(baseType, resolvedTypes);
}
public override string ToString()
{
StringBuilder b = new StringBuilder(genericType.ToString());
b.Append('[');
for (int i = 0; i < typeArguments.Length; i++)
{
if (i > 0)
b.Append(',');
b.Append('[');
b.Append(typeArguments[i].ToString());
b.Append(']');
}
b.Append(']');
return b.ToString();
}
int ISupportsInterning.GetHashCodeForInterning()
{
int hashCode = genericType.GetHashCode();
unchecked
{
foreach (ITypeReference t in typeArguments)
{
hashCode *= 27;
hashCode += t.GetHashCode();
}
}
return hashCode;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ParameterizedTypeReference o = other as ParameterizedTypeReference;
if (o != null && genericType == o.genericType && typeArguments.Length == o.typeArguments.Length)
{
for (int i = 0; i < typeArguments.Length; i++)
{
if (typeArguments[i] != o.typeArguments[i])
return false;
}
return true;
}
return false;
}
}
}

38
ICSharpCode.Decompiler/TypeSystem/PointerType.cs

@ -67,42 +67,4 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -67,42 +67,4 @@ namespace ICSharpCode.Decompiler.TypeSystem
return new PointerType(e);
}
}
[Serializable]
public sealed class PointerTypeReference : ITypeReference, ISupportsInterning
{
readonly ITypeReference elementType;
public PointerTypeReference(ITypeReference elementType)
{
if (elementType == null)
throw new ArgumentNullException(nameof(elementType));
this.elementType = elementType;
}
public ITypeReference ElementType {
get { return elementType; }
}
public IType Resolve(ITypeResolveContext context)
{
return new PointerType(elementType.Resolve(context));
}
public override string ToString()
{
return elementType.ToString() + "*";
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ 91725812;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
PointerTypeReference o = other as PointerTypeReference;
return o != null && this.elementType == o.elementType;
}
}
}

13
ICSharpCode.Decompiler/TypeSystem/SpecialType.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -26,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Contains static implementations of special types.
/// </summary>
[Serializable]
public sealed class SpecialType : AbstractType, ITypeReference
public sealed class SpecialType : AbstractType
{
/// <summary>
/// Gets the type representing resolve errors.
@ -92,20 +92,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -92,20 +92,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
get { return isReferenceType; }
}
IType ITypeReference.Resolve(ITypeResolveContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
return this;
}
#pragma warning disable 809
[Obsolete("Please compare special types using the kind property instead.")]
public override bool Equals(IType other)
{
// We consider a special types equal when they have equal types.
// However, an unknown type with additional information is not considered to be equal to the SpecialType with TypeKind.Unknown.
return other is SpecialType && other.Kind == kind;
return other is SpecialType o && o.Kind == kind;
}
public override int GetHashCode()

13
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -499,19 +499,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -499,19 +499,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
#endregion
#region Resolve on collections
public static IReadOnlyList<IType> Resolve(this IList<ITypeReference> typeReferences, ITypeResolveContext context)
{
if (typeReferences == null)
throw new ArgumentNullException(nameof(typeReferences));
if (typeReferences.Count == 0)
return EmptyList<IType>.Instance;
else
return new ProjectedList<ITypeResolveContext, ITypeReference, IType>(context, typeReferences, (c, t) => t.Resolve(c));
}
#endregion
#region IAssembly.GetTypeDefinition()
/// <summary>
/// Retrieves the specified type in this compilation.

118
ICSharpCode.Decompiler/Util/ProjectedList.cs

@ -1,118 +0,0 @@ @@ -1,118 +0,0 @@
#nullable enable
// 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;
namespace ICSharpCode.Decompiler.Util
{
public sealed class ProjectedList<TInput, TOutput> : IReadOnlyList<TOutput> where TOutput : class
{
readonly IList<TInput> input;
readonly Func<TInput, TOutput> projection;
readonly TOutput?[] items;
public ProjectedList(IList<TInput> input, Func<TInput, TOutput> projection)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (projection == null)
throw new ArgumentNullException(nameof(projection));
this.input = input;
this.projection = projection;
this.items = new TOutput?[input.Count];
}
public TOutput this[int index] {
get {
TOutput? output = LazyInit.VolatileRead(ref items[index]);
if (output != null)
{
return output;
}
return LazyInit.GetOrSet(ref items[index], projection(input[index]));
}
}
public int Count {
get { return items.Length; }
}
public IEnumerator<TOutput> GetEnumerator()
{
for (int i = 0; i < this.Count; i++)
{
yield return this[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public sealed class ProjectedList<TContext, TInput, TOutput> : IReadOnlyList<TOutput> where TOutput : class
{
readonly IList<TInput> input;
readonly TContext context;
readonly Func<TContext, TInput, TOutput> projection;
readonly TOutput?[] items;
public ProjectedList(TContext context, IList<TInput> input, Func<TContext, TInput, TOutput> projection)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
if (projection == null)
throw new ArgumentNullException(nameof(projection));
this.input = input;
this.context = context;
this.projection = projection;
this.items = new TOutput?[input.Count];
}
public TOutput this[int index] {
get {
TOutput? output = LazyInit.VolatileRead(ref items[index]);
if (output != null)
{
return output;
}
return LazyInit.GetOrSet(ref items[index], projection(context, input[index]));
}
}
public int Count {
get { return items.Length; }
}
public IEnumerator<TOutput> GetEnumerator()
{
for (int i = 0; i < this.Count; i++)
{
yield return this[i];
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Loading…
Cancel
Save