title: Why am I getting a generic constraint violation at runtime?
body: <p>I'm getting the following exception while trying to create a new instance of a class that heavily relies on generics:</p>
  
  <pre><code>new TestServer(8888);
  
  System.TypeLoadException
  
  GenericArguments[0], 'TOutPacket', on     
  'Library.Net.Relay`4[TInPacket,TOutPacket,TCryptograph,TEndian]' 
  violates the constraint of type parameter 'TInPacket'.
  
  at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle handle, IntPtr* pInst, Int32 numGenericArgs, ObjectHandleOnStack type)
  at System.RuntimeTypeHandle.Instantiate(Type[] inst)
  at System.RuntimeType.MakeGenericType(Type[] instantiation)
  </code></pre>
  
  <p>I'm puzzled as to why this happens. Aren't generic constraints checked at compile time? </p>
  
  <p>My googling brought me to the conclusion that this has something to do with either of these causes, or (sometimes?) both:</p>
  
  <ul>
  <li>The order in which the generic constraints (<code>where</code>) are defined in the classes;</li>
  <li>The use of the self-referencing generic pattern (conter-intuitive but very legal, see <a href="http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx?PageIndex=1" rel="noreferrer">Eric Lippert's blog post</a>)</li>
  </ul>
  
  <p>One thing I am not ready to sacrifice is the self-referencing pattern. I absolutely need it for a specific purpose.</p>
  
  <p>However, I'd like some help to point out where and why this problem occurs. As the library is massive and makes huge generic patterns, I think it would be best to progressively give code bits on request.</p>
  
  <p>Upon request, declarations again. But I'd like to stress the fact that I would rather know generally why an exception like this can occur and then proceed to fix it myself in my specific code rather than find a specific fix, for posterity. Also, it will be much longer for anyone analyzing the code to answer than to give a general explanation as to why generic type constraints can be violated at runtime.</p>
  
  <p><strong>Implementation declarations:</strong></p>
  
  <pre><code>class TestServer : Server&lt;TestServer, TestClient, ServerPacket.In, ServerPacket.Out, BlankCryptograph, LittleEndianBitConverter&gt;
  
  class TestClient : AwareClient&lt;TestOperationCode, TestServer, TestClient, ServerPacket.In, ServerPacket.Out, BlankCryptograph, LittleEndianBitConverter&gt;
  
  class ServerPacket
  {
      public abstract class In : AwarePacket&lt;TestOperationCode, TestServer, TestClient, ServerPacket.In, ServerPacket.Out, BlankCryptograph, LittleEndianBitConverter&gt;.In
      public class Out : OperationPacket&lt;TestOperationCode, LittleEndianBitConverter&gt;.Out
  }
  
  public enum TestOperationCode : byte
  </code></pre>
  
  <p><strong>Library declarations:</strong></p>
  
  <pre><code>public abstract class Server&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt; : IDisposable
      where TServer : Server&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TClient : Client&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TInPacket : Packet&lt;TEndian&gt;.In
      where TOutPacket : Packet&lt;TEndian&gt;.Out
      where TCryptograph : Cryptograph, new()
      where TEndian : EndianBitConverter, new()
  
  public abstract class Relay&lt;TInPacket, TOutPacket, TCryptograph, TEndian&gt; : IDisposable
      where TInPacket : Packet&lt;TEndian&gt;.In
      where TOutPacket : Packet&lt;TEndian&gt;.Out
      where TCryptograph : Cryptograph, new()
      where TEndian : EndianBitConverter, new()
  
  public abstract class Client&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt; : Relay&lt;TInPacket, TOutPacket, TCryptograph, TEndian&gt;, IDisposable
      where TServer : Server&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TClient : Client&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TInPacket : Packet&lt;TEndian&gt;.In
      where TOutPacket : Packet&lt;TEndian&gt;.Out
      where TCryptograph : Cryptograph, new()
      where TEndian : EndianBitConverter, new()
  
  public abstract class Packet&lt;TEndian&gt; : ByteBuffer&lt;TEndian&gt;, IDisposable 
      where TEndian : EndianBitConverter, new()
  {
      public abstract class In : Packet&lt;TEndian&gt;
      public abstract class Out : Packet&lt;TEndian&gt;
  }
  
  public class OperationPacket&lt;TOperationCode, TEndian&gt; 
      where TEndian : EndianBitConverter, new()
  {
      public class In : Packet&lt;TEndian&gt;.In
      public class Out : Packet&lt;TEndian&gt;.Out
  }
  
  public abstract class AwareClient&lt;TOperationCode, TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt; : Client&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;, IDisposable
      where TCryptograph : Cryptograph, new()
      where TInPacket : AwarePacket&lt;TOperationCode, TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;.In
      where TOutPacket : Packet&lt;TEndian&gt;.Out
      where TServer : Server&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TClient : AwareClient&lt;TOperationCode, TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TEndian : EndianBitConverter, new()
  
  public class AwarePacket&lt;TOperationCode, TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TCryptograph : Cryptograph, new()
      where TInPacket : AwarePacket&lt;TOperationCode, TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;.In
      where TOutPacket : Packet&lt;TEndian&gt;.Out
      where TServer : Server&lt;TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TClient : AwareClient&lt;TOperationCode, TServer, TClient, TInPacket, TOutPacket, TCryptograph, TEndian&gt;
      where TEndian : EndianBitConverter, new()
  {
      public abstract class In : OperationPacket&lt;TOperationCode, TEndian&gt;.In
  }
  </code></pre>
  
  <p>As noted in the comments, the simplest way to get help on this question for me would be to minimize the code to a small and reproducible example in which the bug is still present. However, this is both hard and long for me, and has the high chances of making the bug a heisenbug, as it occurs from complexity.</p>
  
  <p>I tried to isolate it to the following, but I don't get the bug when I do:</p>
  
  <pre><code>// Equivalent of library
  class A&lt;TA, TB, TI, TO&gt; // Client
      where TA : A&lt;TA, TB, TI, TO&gt;
      where TB : B&lt;TA, TB, TI, TO&gt;
      where TI : I
      where TO : O
  { }
  
  class B&lt;TA, TB, TI, TO&gt; // Server
      where TA : A&lt;TA, TB, TI, TO&gt;
      where TB : B&lt;TA, TB, TI, TO&gt;
      where TI : I
      where TO : O
  { }
  
  class I { } // Input packet
  
  class O { } // Output packet
  
  // Equivalent of Aware
  
  class Ii&lt;TA, TB, TI, TO&gt; : I { } // Aware input packet
  
  class Ai&lt;TA, TB, TI, TO&gt; : A&lt;TA, TB, TI, TO&gt; // Aware capable client
      where TA : Ai&lt;TA, TB, TI, TO&gt;
      where TB : B&lt;TA, TB, TI, TO&gt;
      where TI : Ii&lt;TA, TB, TI, TO&gt;
      where TO : O
  { }
  
  // Equivalent of implementation
  
  class XI : Ii&lt;XA, XB, XI, XO&gt; { }
  class XO : O { }
  
  class XA : Ai&lt;XA, XB, XI, XO&gt; { }
  class XB : B&lt;XA, XB, XI, XO&gt; { }
  
  class Program
  {
      static void Main(string[] args)
      {
          new XB(); // Works, so bad isolation
      }
  }
  </code></pre>
  
  <p><strong>Gory Details</strong></p>
  
  <ol>
  <li>Analyzing the exception tells us that <code>TOutPacket</code> violates <code>TInPacket</code> on <code>Relay&lt;TInPacket, TOutPacket, TCryptograph, Tendian&gt;</code>. </li>
  <li>The instance of <code>Relay</code> we have is <code>TestClient</code>, which implements <code>AwareClient</code>, which implements <code>Client</code>, which implements <code>Relay</code>. 
  
  <ul>
  <li><code>AwareClient</code> is used in conjunction with <code>AwarePacket</code> so that both ends are aware of which type of client receives which type of packets.</li>
  </ul></li>
  <li>Therefore, we know that <code>TOutPacket</code> in <code>TestClient</code> violates <code>TInPacket</code> in <code>TestClient</code>.</li>
  <li>The class implementing <code>TOutPacket</code> is <code>ServerPacket.Out</code>, which is a derivative of <code>OperationPacket</code>. This type is relatively simple in terms of generics, as it only provides an enum type and an endian type, making no cross-reference to other classes. Conclusion: The problem is not (most likely) not in this declaration by itself.</li>
  <li>The class implementing <code>TInPacket</code> is <code>ServerPacket.In</code>, which is a derivative of <code>AwarePacket</code>. This type is much more complex than <code>TOutPacket</code>, since it cross-references generics to be <em>aware</em> (<code>AwarePacket</code>) of the client that received it. It is probably in this generic mess that the problem occurs.</li>
  </ol>
  
  <p>Then, many hypotheses can fuse. At this point, what I read is correct and accepted by the compiler, but there is evidently something wrong there. </p>
  
  <p>Can you help me find out why I'm getting a generic constraint violation at runtime with my code?</p>