Я получаю следующее исключение при попытке создать новый экземпляр класса, который в значительной степени полагается на дженерики:
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)
Я не понимаю, почему Бывает. Не проверяются ли общие ограничения во время компиляции?
Поиск в Google привел меня к выводу, что это имеет какое-то отношение к одной из этих причин или (иногда?) К обеим:
где
) в классах; Я не готов жертвовать собой -соответствующий шаблон. Он мне абсолютно необходим для определенной цели.
Однако мне бы хотелось указать, где и почему возникает эта проблема. Поскольку библиотека огромна и создает огромные общие шаблоны, я думаю, что было бы лучше постепенно выдавать биты кода по запросу.
По запросу, снова объявления. Но я хотел бы подчеркнуть тот факт, что я предпочел бы в целом знать, почему может возникнуть подобное исключение, и затем приступить к его исправлению в моем конкретном коде, а не искать конкретное исправление для потомков. Кроме того, любому, кто анализирует код, потребуется гораздо больше времени, чтобы ответить, чем дать общее объяснение того, почему ограничения универсального типа могут быть нарушены во время выполнения.
Объявления реализации:
class TestServer : Server
class TestClient : AwareClient
class ServerPacket
{
public abstract class In : AwarePacket.In
public class Out : OperationPacket.Out
}
public enum TestOperationCode : byte
Объявления библиотеки:
public abstract class Server : IDisposable
where TServer : Server
where TClient : Client
where TInPacket : Packet.In
where TOutPacket : Packet.Out
where TCryptograph : Cryptograph, new()
where TEndian : EndianBitConverter, new()
public abstract class Relay : IDisposable
where TInPacket : Packet.In
where TOutPacket : Packet.Out
where TCryptograph : Cryptograph, new()
where TEndian : EndianBitConverter, new()
public abstract class Client : Relay, IDisposable
where TServer : Server
where TClient : Client
where TInPacket : Packet.In
where TOutPacket : Packet.Out
where TCryptograph : Cryptograph, new()
where TEndian : EndianBitConverter, new()
public abstract class Packet : ByteBuffer, IDisposable
where TEndian : EndianBitConverter, new()
{
public abstract class In : Packet
public abstract class Out : Packet
}
public class OperationPacket
where TEndian : EndianBitConverter, new()
{
public class In : Packet.In
public class Out : Packet.Out
}
public abstract class AwareClient : Client, IDisposable
where TCryptograph : Cryptograph, new()
where TInPacket : AwarePacket.In
where TOutPacket : Packet.Out
where TServer : Server
where TClient : AwareClient
where TEndian : EndianBitConverter, new()
public class AwarePacket
where TCryptograph : Cryptograph, new()
where TInPacket : AwarePacket.In
where TOutPacket : Packet.Out
where TServer : Server
where TClient : AwareClient
where TEndian : EndianBitConverter, new()
{
public abstract class In : OperationPacket.In
}
Как указано в комментариев, самый простой способ получить помощь по этому вопросу для меня - свести код к небольшому и воспроизводимому примеру, в котором ошибка все еще присутствует. Однако для меня это одновременно и сложно, и долго, и у меня есть высокие шансы превратить ошибку в heisenbug, поскольку это происходит из-за сложности.
Я пытался изолировать ее от следующего, но я не получаю ошибку, когда Я делаю:
// Equivalent of library
class A // Client
where TA : A
where TB : B
where TI : I
where TO : O
{ }
class B // Server
where TA : A
where TB : B
where TI : I
where TO : O
{ }
class I { } // Input packet
class O { } // Output packet
// Equivalent of Aware
class Ii : I { } // Aware input packet
class Ai : A // Aware capable client
where TA : Ai
where TB : B
where TI : Ii
where TO : O
{ }
// Equivalent of implementation
class XI : Ii { }
class XO : O { }
class XA : Ai { }
class XB : B { }
class Program
{
static void Main(string[] args)
{
new XB(); // Works, so bad isolation
}
}
Gory Details
TOutPacket
нарушает TInPacket
на Relay
. Relay
TestClient
, который реализует AwareClient
, который реализует Client
, который реализует Relay
.
AwareClient
используется вместе с AwarePacket
, поэтому оба конца знают, какой тип клиента получает какой тип пакетов. TOutPacket
] в TestClient
нарушает TInPacket
в TestClient
. TOutPacket
, - ServerPacket.Out
, который является производным от OperationPacket
. Этот тип относительно прост с точки зрения универсальных шаблонов, поскольку он предоставляет только перечислимый тип и конечный тип, не делая перекрестных ссылок на другие классы. Заключение: проблема (скорее всего) не в этом объявлении. TInPacket
, - это ServerPacket.In
, который является производным от AwarePacket
. Этот тип намного сложнее, чем TOutPacket
, поскольку он перекрестно ссылается на дженерики, чтобы знать ( AwarePacket
) клиента, который его получил. Вероятно, именно в этом беспорядке и возникает проблема. Тогда многие гипотезы могут сливаться. На данный момент то, что я прочитал, правильно и принято компилятором, но, очевидно, что-то не так.
Можете ли вы помочь мне выяснить, почему я получаю общее нарушение ограничения во время выполнения с моим кодом?