わかった。これは完全な分析ではありませんが、ILをいじっても、これができるかどうかを判断するには十分な分析だと思います。私が知る限り、これはできません。
また、dotPeekを使用して逆コンパイルされたバージョンを見ると、属性ごとに、またはその他の方法で、その特定のタイプ/その中の特定のタイプについて特別なことは何もわかりませんでした。
namespace System
{
/// <summary>
/// Describes objects that contain both a managed pointer to a location and a runtime representation of the type that may be stored at that location.
/// </summary>
/// <filterpriority>2</filterpriority>
[ComVisible(true)]
[CLSCompliant(false)]
public struct TypedReference
{
それで、System.Reflection.Emitを使用してそのようなクラスを作成してみました。
namespace NonStorableTest
{
//public class Invalid
//{
// public TypedReference i;
//}
class Program
{
static void Main(string[] args)
{
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("EmitNonStorable"),
AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule("EmitNonStorable", "EmitNonStorable.dll");
TypeBuilder invalidBuilder = moduleBuilder.DefineType("EmitNonStorable.Invalid",
TypeAttributes.Class | TypeAttributes.Public);
ConstructorBuilder constructorBuilder = invalidBuilder.DefineDefaultConstructor(MethodAttributes.Public);
FieldBuilder fieldI = invalidBuilder.DefineField("i", typeof (TypedReference), FieldAttributes.Public);
invalidBuilder.CreateType();
asmBuilder.Save("EmitNonStorable.dll");
Console.ReadLine();
}
}
}
つまり、実行すると、TypeLoadExceptionがスローされ、そのスタックトレースはSystem.Reflection.Emit.TypeBuilder.TermCreateClassを指します。それで、私はその後、逆コンパイラーを使用して、これを取得しました。
[SuppressUnmanagedCodeSecurity]
[SecurityCritical]
[DllImport("QCall", CharSet = CharSet.Unicode)]
private static void TermCreateClass(RuntimeModule module, int tk, ObjectHandleOnStack type);
CLRの管理されていない部分を指しています。この時点で、負けないように、CLRの参照バージョンの共有ソースを掘り下げました。この答えがすべての合理的な使用を超えて肥大化するのを避けるために、私が行ったすべてのトレースを実行することはしませんが、最終的には、MethodTableBuilder::SetupMethodTable2関数の\clr\ src \ vm \ class.cppになります(これは、フィールド記述子を設定しているようにも見えます)、次の行があります。
// Mark the special types that have embeded stack poitners in them
if (strcmp(name, "ArgIterator") == 0 || strcmp(name, "RuntimeArgumentHandle") == 0)
pClass->SetContainsStackPtr();
と
if (pMT->GetInternalCorElementType() == ELEMENT_TYPE_TYPEDBYREF)
pClass->SetContainsStackPtr();
この後者は、\ src \ inc \ cortypeinfo.hにある情報に関連しているため、次のようになります。
// This describes information about the COM+ primitive types
// TYPEINFO(enumName, className, size, gcType, isArray,isPrim, isFloat,isModifier)
[...]
TYPEINFO(ELEMENT_TYPE_TYPEDBYREF, "System", "TypedReference",2*sizeof(void*), TYPE_GC_BYREF, false, false, false, false)
(実際には、そのリストで唯一のELEMENT_TYPE_TYPEDBYREFタイプです。)
次に、ContainsStackPtr()は、フィールドなど、特定のタイプが使用されないようにするために、さまざまな場所で使用されます-\ src \ vm \ class.cp、MethodTableBuilder :: InitializeFieldDescs()から:
// If it is an illegal type, say so
if (pByValueClass->ContainsStackPtr())
{
BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
}
とにかく:長い、長い、長い話を短くするために、この方法で保存できないタイプが効果的にCLRにハードコードされている場合があります。したがって、リストを変更したい場合、タイプを保存不可としてフラグを立てるIL手段を提供する場合、Monoまたは共有ソースCLRを使用して、独自のバージョンをスピンオフする必要があります。