Take the 2-minute tour ×
  • Is there a way to mark a type (or even better, an interface) so that no instances of it can be stored in a field (in a similar way to TypedReference and ArgIterator)?
  • In the same way, is there a way to prevent instances from being passed through anonymous methods and -- In general -- To mimic the behavior of the two types above?
  • Can this be done through ILDasm or more generally through IL editing? Since UnconstrainedMelody achieves normally unobtainable results through binary editing of a compiled assembly, maybe there's a way to "mark" certain types (or even better, abstract ones or marker interfaces) through the same approach.

I doubt it’s hardcoded in the compiler because the documentation for the error CS0610 states:

There are some types that cannot be used as fields or properties. These types include...

Which in my opinion hints that the set of types like those can be extended -- But I could be wrong.

I've searched a bit on SO and while I understand that throwing a compiler error programmatically can't be done, I could find no source stating that certain "special" types' behaviors couldn't be replicated.

Even if the question is mostly academic, there could be some usages for an answer. For example, it could be useful sometimes to be sure that a certain object's lifetime is constrained to the method block which creates it.

EDIT: RuntimeArgumentHandle is one more (unmentioned) non-storable type.

EDIT 2: If it can be of any use, it seems that the CLR treats those types in a different way as well, if not only the compiler (still assuming that the types are in no way different from others). The following program, for example, will throw a TypeLoadException regarding TypedReference*. I've adapted it to make it shorter but you can work around it all you want. Changing the pointer's type to, say, void* will not throw the exception.

using System;

unsafe static class Program
    static TypedReference* _tr;

    static void Main(string[] args)
        _tr = (TypedReference*) IntPtr.Zero;
share|improve this question
I wouldn't be at all surprised if it were hard-coded, btw. Just because the documentation doesn't want to pin it down doesn't mean that's not the way it's done in the compiler. –  Jon Skeet Jan 16 '13 at 16:05
I think the same thing, but I'll have to check. –  Kendall Frey Jan 16 '13 at 16:10
CS0611 is a related error, although probably the solution to either would apply to both. –  Eve Jan 16 '13 at 16:18
add comment

2 Answers

up vote 5 down vote accepted

Okay. This isn't quite a complete analysis, but I suspect it's a sufficient one for the purposes of determining whether you can do this, even by twiddling IL - which, so far as I can tell, you can't.

I also, on looking at the decompiled version with dotPeek, couldn't see anything special about that particular type/those particular types in there, attribute-wise or otherwise:

namespace System
  /// <summary>
  /// </summary>
  /// <filterpriority>2</filterpriority>
  public struct TypedReference

So, that done, I tried creating such a class using 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"),

            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);



That, when you run it, throws a TypeLoadException, the stack trace of which points you to System.Reflection.Emit.TypeBuilder.TermCreateClass. So then I went after that with the decompiler, which gave me this:

[DllImport("QCall", CharSet = CharSet.Unicode)]
private static void TermCreateClass(RuntimeModule module, int tk, ObjectHandleOnStack type);

Pointing into the unmanaged parts of the CLR. At this point, not to be defeated, I dug into the shared sources for the reference version of the CLR. I won't go through all the tracing through that I did, to avoid bloating this answer beyond all reasonable use, but eventually, you end up in \clr\src\vm\class.cpp, in the MethodTableBuilder::SetupMethodTable2 function (which also appears to set up field descriptors), where you find these lines:

// Mark the special types that have embeded stack poitners in them
                        if (strcmp(name, "ArgIterator") == 0 || strcmp(name, "RuntimeArgumentHandle") == 0)


if (pMT->GetInternalCorElementType() == ELEMENT_TYPE_TYPEDBYREF)

This latter relating to information found in \src\inc\cortypeinfo.h, thus:

// 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)

(It's actually the only ELEMENT_TYPE_TYPEDBYREF type in that list.)

ContainsStackPtr() is then in turn used elsewhere in various places to prevent those particular types from being used, including in fields - from \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);

Anyway: to cut a long, long, long story short, it would seem to be the case that which types are non-storable in this way is effectively hard-coded into the CLR, and thus that if you want to change the list or provide an IL means to flag up types as non-storable, you're pretty much going to have to take Mono or the shared-source CLR and spin off your own version.

share|improve this answer
Great answer, I think that settles it. –  Eve Jan 20 '13 at 12:22
add comment

I couldn't find anything in the IL that indicated those types are in any way special. I do know that the compiler has many, many special cases, such as transforming int/Int32 into the internal type int32, or many things pertaining to the Nullable struct. I highly suspect these types are also special cases.

A possible solution would be Roslyn, which I expect would let you create such a constraint.

share|improve this answer
I haven't looked much into Roslyn yet but I assume that the end-user, using a regular compiler, wouldn't be affected by the constraint. I'll wait to see if someone can come up with a counter-argument or a confirmation (by examining the compiler, somehow). –  Eve Jan 16 '13 at 16:41
@Eve I'd assume that if you're doing something as rare as this, that you would be able to use Roslyn without a problem. Of course, if it's a public type, you may not be able to do that. –  Kendall Frey Jan 16 '13 at 16:50
How exactly do you think Roslyn would help? –  svick Jan 16 '13 at 16:52
@svick Roslyn would let you prevent compilation of code that would violate the requirements. –  Kendall Frey Jan 16 '13 at 16:56
add comment

Your Answer


