BenMcLean
BenMcLean
CC#
Created by BenMcLean on 8/7/2024 in #help
OOP design pattern question
I have an interface called IModel for voxel models. I don't want to change it because it has lots of existing implementations without a base class. There are about a dozen different operations that can be done on the IModel interface. Currently these are static methods in a static class with no global state. Certain special implementations of IModel have special implementations of some of these methods that get the same result more efficiently from taking advantage of their internal data structures beyond what IModel offers. These are only available for some operations on some IModel implementations some of the time, not consistently. I want to make it so that when user code calls one of these operations, the program will choose the more efficient special implementation when available or resort to the default IModel version if not available. What OOP design pattern should I be following to make that happen?
30 replies
CC#
Created by BenMcLean on 6/22/2024 in #help
Collections expression to add an item at the start.
I've got this:
public uint[] Palette => [.. (new List<uint> { 0u }), .. Colors.Take(255)];
public uint[] Palette => [.. (new List<uint> { 0u }), .. Colors.Take(255)];
What I intend for it to do is to return an array of uints which starts with zero as the first value, then appends the contents of Colors (another array of uint) up to a maximum of 255 items, so that this array can never be larger than 256 items. This expression I've got appears to work, technically, but it also appears that I should be able to do this without creating a new List<uint> just to add that one item. I'm almost certian there's some expression I could include which wouldn't require that. Anyone know?
22 replies
CC#
Created by BenMcLean on 6/9/2024 in #help
Binary serialization / deserialization where you don't control the format
I wrote this:
public static string ReadPascalString(BinaryReader reader) => System.Text.Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadUInt16()));
public static void WritePascalString(BinaryWriter writer, string s)
{
writer.Write((ushort)s.Length);
writer.Write(System.Text.Encoding.UTF8.GetBytes(s));
}
[Serializable]
public readonly record struct HeaderChunk(
string Name,
string Type,
int ID,
int ReferenceID,
bool Visible,
bool Locked,
uint Color,
float PivotX,
float PivotY,
float PivotZ) : ISerializable
{
public static HeaderChunk Read(Stream stream)
{
BinaryReader reader = new(stream);
return new(
Name: ReadPascalString(reader),
Type: ReadPascalString(reader),
ID: reader.ReadUInt16(),
ReferenceID: reader.ReadUInt16(),
Visible: reader.ReadBoolean(),
Locked: reader.ReadBoolean(),
Color: reader.ReadUInt32(),
PivotX: reader.ReadSingle(),
PivotY: reader.ReadSingle(),
PivotZ: reader.ReadSingle());
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();//Help?
}

public void Write(Stream stream)
{
BinaryWriter writer = new(stream);
WritePascalString(writer, Name);
WritePascalString(writer, Type);
writer.Write(ID);
writer.Write(ReferenceID);
writer.Write(Visible);
writer.Write(Locked);
writer.Write(Color);
writer.Write(PivotX);
writer.Write(PivotY);
writer.Write(PivotZ);
}
}
public static string ReadPascalString(BinaryReader reader) => System.Text.Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadUInt16()));
public static void WritePascalString(BinaryWriter writer, string s)
{
writer.Write((ushort)s.Length);
writer.Write(System.Text.Encoding.UTF8.GetBytes(s));
}
[Serializable]
public readonly record struct HeaderChunk(
string Name,
string Type,
int ID,
int ReferenceID,
bool Visible,
bool Locked,
uint Color,
float PivotX,
float PivotY,
float PivotZ) : ISerializable
{
public static HeaderChunk Read(Stream stream)
{
BinaryReader reader = new(stream);
return new(
Name: ReadPascalString(reader),
Type: ReadPascalString(reader),
ID: reader.ReadUInt16(),
ReferenceID: reader.ReadUInt16(),
Visible: reader.ReadBoolean(),
Locked: reader.ReadBoolean(),
Color: reader.ReadUInt32(),
PivotX: reader.ReadSingle(),
PivotY: reader.ReadSingle(),
PivotZ: reader.ReadSingle());
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();//Help?
}

public void Write(Stream stream)
{
BinaryWriter writer = new(stream);
WritePascalString(writer, Name);
WritePascalString(writer, Type);
writer.Write(ID);
writer.Write(ReferenceID);
writer.Write(Visible);
writer.Write(Locked);
writer.Write(Color);
writer.Write(PivotX);
writer.Write(PivotY);
writer.Write(PivotZ);
}
}
The purpose of this is binary serialization/deserialization to/from a file format I don't control. It has to exactly match that format. The question is, how would I convert my naïve Read and Write methods into something that would properly implement Serializable and ISerializable the idiomatic C# way?
8 replies
CC#
Created by BenMcLean on 12/29/2023 in #help
Turtle moving question
Given this test here:
public void TurtleTest()
{
static ushort expected(ushort startX, ushort startY, ushort newY, bool yFirst = false)
{
ushort x = startX,
y = startY;
while (y != newY)
{
if (yFirst && x - startX < y - startY
|| !yFirst && x - startX <= y - startY)
x++;
else
y++;
}
return x;
}
static ushort actual(ushort startX, ushort startY, ushort newY, bool yFirst = false) => (ushort)(startX + newY - startY);
for (ushort startX = 0; startX < 9; startX++)
for (ushort startY = 0; startY < 9; startY++)
for (ushort newY = startY; newY < startY + 9; newY++)
{
Assert.Equal(
expected: expected(startX, startY, newY, false),
actual: actual(startX, startY, newY, false));
Assert.Equal(
expected: expected(startX, startY, newY, true),
actual: actual(startX, startY, newY, true));
}
}
public void TurtleTest()
{
static ushort expected(ushort startX, ushort startY, ushort newY, bool yFirst = false)
{
ushort x = startX,
y = startY;
while (y != newY)
{
if (yFirst && x - startX < y - startY
|| !yFirst && x - startX <= y - startY)
x++;
else
y++;
}
return x;
}
static ushort actual(ushort startX, ushort startY, ushort newY, bool yFirst = false) => (ushort)(startX + newY - startY);
for (ushort startX = 0; startX < 9; startX++)
for (ushort startY = 0; startY < 9; startY++)
for (ushort newY = startY; newY < startY + 9; newY++)
{
Assert.Equal(
expected: expected(startX, startY, newY, false),
actual: actual(startX, startY, newY, false));
Assert.Equal(
expected: expected(startX, startY, newY, true),
actual: actual(startX, startY, newY, true));
}
}
How do I rewrite the actual method to always give the same output as the expected method?
6 replies
CC#
Created by BenMcLean on 12/17/2023 in #help
✅ Safe type casting with LINQ?
As part of an octree I'm implementing, I have this line:
foreach (Leaf leaf in popped.Where(node => node is Leaf).Cast<Leaf>())
foreach (Leaf leaf in popped.Where(node => node is Leaf).Cast<Leaf>())
popped enumerates type Node. Type Leaf is a child class of Node. My question is, can I do this Where and Cast in a single operation which is type safe or does that line look correct as-is?
5 replies
CC#
Created by BenMcLean on 11/25/2023 in #help
LINQ to keep adding items until a fixed length is reached?
Let's say I have a LINQ collection of uint some length less than 256 and I want to keep adding 0u until it reaches length 256. If the length is already 256 or higher then this method should do nothing. Can I do that with LINQ? If so, what would be the method for that?
23 replies
CC#
Created by BenMcLean on 10/2/2023 in #help
❔ Combine two arrays by alternating items?
Let's imagine I have two arrays, A and B, which each have four items. I want to make a new array C which is made up of the contents of A and B. so
T[] c = new T[a.Length + b.Length];//8
c[0]=a[0];
c[1]=b[0];
c[2]=a[1];
c[3]=b[1];
c[4]=a[2];
c[5]=b[2];
c[6]=a[3];
c[7]=b[3];
T[] c = new T[a.Length + b.Length];//8
c[0]=a[0];
c[1]=b[0];
c[2]=a[1];
c[3]=b[1];
c[4]=a[2];
c[5]=b[2];
c[6]=a[3];
c[7]=b[3];
Except can I do this with LINQ? And for any arbitrary size?
38 replies
CC#
Created by BenMcLean on 3/24/2023 in #help
❔ Casting range to bytes?
byte[] bytes = Enumerable.Range(0, 256).Cast<byte>().ToArray();
byte[] bytes = Enumerable.Range(0, 256).Cast<byte>().ToArray();
The result: System.InvalidCastException : Unable to cast object of type 'System.Int32' to type 'System.Byte'. Why? This should work! Why doesn't this work!?
16 replies
CC#
Created by BenMcLean on 1/29/2023 in #help
❔ LINQ build an array with an arbitrary value at the start
So, I want to make a palette that's an array of ints where index 0 is equal to 0 and the rest repeat a rainbow pattern.
public static readonly ReadOnlyCollection<int> Rainbow = Array.AsReadOnly(new int[7]
{ // Just a color test, not a political statement.
unchecked((int)0xFF0000FF),//Red
unchecked((int)0xFFA500FF),//Orange
unchecked((int)0xFFFF00FF),//Yellow
0x00FF00FF,//Green
0x0000FFFF,//Blue
0x4B0082FF,//Indigo
unchecked((int)0x8F00FFFF)//Violet
});
public static int[] RainbowPalette()
{
int[] palette = new int[byte.MaxValue];
for (int index = 1; index < palette.Length; index++)
palette[index] = Rainbow[(index - 1) % Rainbow.Count];
return palette;
}
public static readonly ReadOnlyCollection<int> Rainbow = Array.AsReadOnly(new int[7]
{ // Just a color test, not a political statement.
unchecked((int)0xFF0000FF),//Red
unchecked((int)0xFFA500FF),//Orange
unchecked((int)0xFFFF00FF),//Yellow
0x00FF00FF,//Green
0x0000FFFF,//Blue
0x4B0082FF,//Indigo
unchecked((int)0x8F00FFFF)//Violet
});
public static int[] RainbowPalette()
{
int[] palette = new int[byte.MaxValue];
for (int index = 1; index < palette.Length; index++)
palette[index] = Rainbow[(index - 1) % Rainbow.Count];
return palette;
}
Question: How could I get this same result with LINQ?
33 replies
CC#
Created by BenMcLean on 1/27/2023 in #help
✅ dumb question involving Math.Max
Given that a and b are 32-bit integers within the range of -100 to 100, this should always return True right?
int first = a < b ? 0 : a - b;
int second = Math.Max(a - b, 0);
return first == second;
int first = a < b ? 0 : a - b;
int second = Math.Max(a - b, 0);
return first == second;
8 replies
CC#
Created by BenMcLean on 12/19/2022 in #help
❔ Return groups of results using LINQ?
I'm iterating through a set of data with LINQ. The data's broken up into sections, where there's a "1" in the "NewSection" column on the first row of a new section, otherwise there's a "0" in that column. I want to make a function that returns an Enumerable of Enumerables of my data rows, where the inner enumerable is all the entries in each section. How would I construct my loop for this?
19 replies