Files
2026-03-30 20:11:57 +07:00

209 lines
5.5 KiB
C#

//
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2015 Jb Evain
// Copyright (c) 2008 - 2011 Novell, Inc.
//
// Licensed under the MIT/X11 license.
//
using MonoFN.Collections.Generic;
using System;
using System.Diagnostics;
using System.Threading;
namespace MonoFN.Cecil
{
public struct CustomAttributeArgument
{
public TypeReference Type { get; }
public object Value { get; }
public CustomAttributeArgument(TypeReference type, object value)
{
Mixin.CheckType(type);
this.Type = type;
this.Value = value;
}
}
public struct CustomAttributeNamedArgument
{
public string Name { get; }
public CustomAttributeArgument Argument { get; }
public CustomAttributeNamedArgument(string name, CustomAttributeArgument argument)
{
Mixin.CheckName(name);
this.Name = name;
this.Argument = argument;
}
}
public interface ICustomAttribute
{
TypeReference AttributeType { get; }
bool HasFields { get; }
bool HasProperties { get; }
bool HasConstructorArguments { get; }
Collection<CustomAttributeNamedArgument> Fields { get; }
Collection<CustomAttributeNamedArgument> Properties { get; }
Collection<CustomAttributeArgument> ConstructorArguments { get; }
}
[DebuggerDisplay("{AttributeType}")]
public sealed class CustomAttribute : ICustomAttribute
{
internal CustomAttributeValueProjection projection;
internal readonly uint signature;
internal bool resolved;
private byte[] blob;
internal Collection<CustomAttributeArgument> arguments;
internal Collection<CustomAttributeNamedArgument> fields;
internal Collection<CustomAttributeNamedArgument> properties;
public MethodReference Constructor { get; set; }
public TypeReference AttributeType
{
get { return Constructor.DeclaringType; }
}
public bool IsResolved
{
get { return resolved; }
}
public bool HasConstructorArguments
{
get
{
Resolve();
return !arguments.IsNullOrEmpty();
}
}
public Collection<CustomAttributeArgument> ConstructorArguments
{
get
{
Resolve();
if (arguments == null)
Interlocked.CompareExchange(ref arguments, new(), null);
return arguments;
}
}
public bool HasFields
{
get
{
Resolve();
return !fields.IsNullOrEmpty();
}
}
public Collection<CustomAttributeNamedArgument> Fields
{
get
{
Resolve();
if (fields == null)
Interlocked.CompareExchange(ref fields, new(), null);
return fields;
}
}
public bool HasProperties
{
get
{
Resolve();
return !properties.IsNullOrEmpty();
}
}
public Collection<CustomAttributeNamedArgument> Properties
{
get
{
Resolve();
if (properties == null)
Interlocked.CompareExchange(ref properties, new(), null);
return properties;
}
}
internal bool HasImage
{
get { return Constructor != null && Constructor.HasImage; }
}
internal ModuleDefinition Module
{
get { return Constructor.Module; }
}
internal CustomAttribute(uint signature, MethodReference constructor)
{
this.signature = signature;
this.Constructor = constructor;
resolved = false;
}
public CustomAttribute(MethodReference constructor)
{
this.Constructor = constructor;
resolved = true;
}
public CustomAttribute(MethodReference constructor, byte[] blob)
{
this.Constructor = constructor;
resolved = false;
this.blob = blob;
}
public byte[] GetBlob()
{
if (blob != null)
return blob;
if (!HasImage)
throw new NotSupportedException();
return Module.Read(ref blob, this, (attribute, reader) => reader.ReadCustomAttributeBlob(attribute.signature));
}
private void Resolve()
{
if (resolved || !HasImage)
return;
lock (Module.SyncRoot)
{
if (resolved)
return;
Module.Read(this, (attribute, reader) =>
{
try
{
reader.ReadCustomAttributeSignature(attribute);
resolved = true;
}
catch (ResolutionException)
{
if (arguments != null)
arguments.Clear();
if (fields != null)
fields.Clear();
if (properties != null)
properties.Clear();
resolved = false;
}
});
}
}
}
}