В свете вашего недавнего редактирования:
Причина, по которой мне нужны типы значений, состоит в том, чтобы я мог создать их массив и передать его в OpenGL в качестве буфера вершин.Для этого данные должны быть непосредственно включены в этот массив.
Похоже, что решение real для вас - инкапсуляция.Если макет вашего struct
продиктован сторонним API (так что вы можете взаимодействовать с неуправляемым кодом), тогда вам действительно следует рассмотреть обертывание типов API в соответствующих классах, а не пытаться взаимодействовать с ними непосредственно в коде.
Например, вы утверждаете это:
Мне нужно это как структура, потому что это должен быть тип значения.И мне нужно наследование, потому что мне нужен универсальный массив и методы, которые я могу гарантировать.
Это не будет так, как вы ожидаете.Как уже отмечали другие, единственный способ определить набор общих функций, которые могут применяться к структурам, - через интерфейсы (например, примитивные типы в .NET реализуют IComparable
).К сожалению, если вы объявите массив типа IYourInterface
, все значения будут упакованы (ссылки на интерфейсы являются ссылочными типами, даже если базовое значение, на которое они указывают, является типами значений).
Например, допустим, вы объявляете интерфейс IVertex
:
public interface IVertex
{
int SizeInBytes { get; }
void SetPointers();
}
И у вас есть один или несколько типов значений, которые его реализуют:
struct ColorVertex : IVertex
{
Vector3 Position;
Vector4 Color;
override int SizeInBytes //static
{
get { return (3 + 4) * 4; }
}
override void SetVertexPointers() //static
{
...
}
}
Всякий раз, когда вы делаете это:
ColorVertex myVertex = new ColorVertex();
IVertex foo = myVertex;
Во второй строке будет указано значение myVertex
и сохранена ссылка на это упакованное значение в foo
.Поскольку массивы - это просто последовательность переменных, применяются те же правила:
IVertex[] foos = { myVertex };
Все значения в foos
будут упакованы, а их ссылки сохранены.Это отличается от того, что вы сделали:
ColorVertex[] colors = { myVertex };
Там, где нет необходимости в боксе.
Это имеет значение, непосредственно связанное с тем, что вы ищете, так как бокс значений теперь означает, что вы небольше иметь непрерывный блок значений (ну, вы делаете, но непрерывный блок просто ссылки; сами значения лежат в другом месте).
Инкапсуляция
Учитывая фактчто у вас
- есть сторонний API с определенным типом, с которым вам нужно взаимодействовать
- Требование поддержки различных вариантов использования в вашем коде и желание использовать объектно-ориентированныйчтобы создать шаблоны для этого
Вы действительно должны рассмотреть обертывание OpenGL API.Например, предположим, что у вас есть следующее:
// OpenGL type
struct Vertex
{
int SizeInBytes;
}
public static extern void OpenGLFunction(Vertex[] vertices);
Вероятно, лучшим вариантом было бы определить собственный интерфейс, а затем скрыть API OpenGL:
public abstract class VertexBase
{
internal Vertex ToVertex()
{
// your logic here
}
}
public static class OpenGL
{
public static void WrappedFunction(VertexBase[] vertices)
{
Vertex[] outVertices = new Vertex[vertices.Length];
for(int i = 0; i < vertices.Length; i++)
{
outVertices[i] = vertices[i].ToVertex();
}
OpenGLFunction(outVertices);
}
}
(Это, очевидно, надуманный пример, но он должен продемонстрировать то, что я пытаюсь донести до уровня в плане введения уровня абстракции между вашим кодом и другим API)