i have some problem with serialization in C#
Have Code:
public struct CoOrds
{
public double x, y, z;
public CoOrds(double p1, double p2, double p3)
{
x = p1;
y = p2;
z = p3;
}
}
public struct printColor
{
public int r, g, b;
public printColor(int p1, int p2, int p3)
{
r = p1;
g = p2;
b = p3;
}
}
[Serializable]
public abstract class shape : ISerializable
{
public int borderStyle=1;
/* ===============================COLOR PARAMETERS================================ */
public printColor colorRGB = new printColor(0, 0, 0);
public System.Drawing.Drawing2D.DashStyle styleLine { get; set; }
public int widht=2;
/*=================================FILL PARAMETERS=====================================*/
public printColor fillColorRGB = new printColor(255,255, 255);
public shape()
{
}
protected shape(SerializationInfo info, StreamingContext context)
{
colorRGB.r = info.GetInt32("colorLine.r");
colorRGB.g = info.GetInt32("colorLine.g");
colorRGB.b = info.GetInt32("colorLine.b");
borderStyle = info.GetInt32("borderStyle");
fillColorRGB.r = info.GetInt32("fillColorRGB.r");
fillColorRGB.g = info.GetInt32("fillColorRGB.g");
fillColorRGB.b = info.GetInt32("fillColorRGB.b");
widht = info.GetInt32("widht");
}
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("colorLine.r",colorRGB.r);
info.AddValue("colorLine.g", colorRGB.g);
info.AddValue("colorLine.b", colorRGB.b);
info.AddValue("borderStyle",borderStyle);
info.AddValue("fillColorRGB.r", fillColorRGB.r);
info.AddValue("fillColorRGB.g", fillColorRGB.g);
info.AddValue("fillColorRGB.b", fillColorRGB.b);
info.AddValue("widht", widht);
}
.....
1. how i can serializable struct like
[Serializable]
public struct CoOrds
under the class and how the put it in shape and GetObjectData, because i have too many classes where i must use this struct
Thx
You can directly serialize it with info.AddValue("Pos", pos, typeof(CoOrds) or you can convert to/from string.
[Serializable()]
public struct Coords
{
readonly public double x, y, z;
public Coords(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
public static Coords FromString(string value)
{
if (string.IsNullOrEmpty(value)) return new Coords();
double x = 0,y= 0,z = 0;
string[] parts = value.Split(',');
if (parts.Length > 0) double.TryParse(parts[0], out x);
if (parts.Length > 1) double.TryParse(parts[1], out y);
if (parts.Length > 2) double.TryParse(parts[2], out z);
return new Coords(x, y, z);
}
public override string ToString()
{
//Ensure round-trip formatting
return string.Format("{0:R},{1:R},{2:R}", x, y, z);
}
}
and then serialize it with
[Serializable()]
public class Vertex : ISerializable
{
public Coords pos1, pos2;
...
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Pos1", pos1.ToString());
info.AddValue("Pos2", pos2, typeof(Coords));
}
public Vertex(SerializationInfo info, StreamingContext context)
{
this.pos1 = Coords.FromString(info.GetValue("Pos1", typeof(string)) as string);
this.pos2 = (Coords)info.GetValue("Pos2", typeof(Coords));
}
}
With work equally well with the test code I did.
Related
I have the following classes:
public class Grid<T>
{
public int Width { get; }
public int Height { get; }
public float CellSize { get; }
public Vector2 GridOffset { get; }
public T[,] GridObjects { get; }
public Grid(int width, int height, float cellSize, Vector3 gridOffset, Func<Grid<T>, int, int, T> createGridObjectMethod)
{
this.Width = width;
this.Height = height;
this.CellSize = cellSize;
this.GridOffset = gridOffset;
GridObjects = new T[width, height];
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
GridObjects[x, y] = createGridObjectMethod(this, x, y);
}
}
}
}
public interface IPathNode
{
PathNode GetPathNode();
}
public class PathNode : IPathNode
{
private readonly Grid<IPathNode> grid;
public int X { get; }
public int Y { get; }
public PathNode PreviousNode;
public PathNode(Grid<IPathNode> grid, int x, int y)
{
this.grid = grid;
this.X = x;
this.Y = y;
}
}
Now, I'm trying to create a Grid instance with the following line:
grid = new Grid<PathNode>(10, 10, 1, new Vector3(-5, -5, 0), (g, x, y) =>
{
Grid<IPathNode> test = (Grid<IPathNode>)g;
return new PathNode(g, x, y);
});
The problem is that PathNode asks for a Grid and my grid is made of PathNodes (or any other type that implements that interface).
How can I cast it, or instantiate it?
Tried casting the grid object, but it will fail to compile.
Also adding generics to the PathNode class but I don't like that
I ended up adding a restriction to the PathNode and the interface (and adding generics to it). I had to edit some of the code but it works. Don't really like this option since I only use the generics for it to work but yeah.
public class PathNode<T> : IPathNode<T> where T : IPathNode<T>
public interface IPathNode<T> where T : IPathNode<T>
Problem Statement
There is a custom vector class:
namespace StackoverflowQuestion1
{
public class MyVector
{
public float x;
public float y;
public float z;
public MyVector(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
}
There is an interface for anything that's movable, which means positions may change:
namespace StackoverflowQuestion1
{
public interface IMovable
{
public string Name { get; }
public MyVector Position { get; }
}
}
Furniture is movable, therefore it implements the corresponding interface:
namespace StackoverflowQuestion1
{
public class Furniture : IMovable
{
public string Name { get; private set; }
public MyVector Position { get; private set; }
public Furniture(string name, float x, float y, float z)
{
this.Name = name;
this.Position = new MyVector(x, y, z);
}
}
}
Accessing the private getter of the Name is not possible, as expected. Accessing the private setter of Position is also not working, as expected. However, accessing the fields of Position is possible, as they are public.
using StackoverflowQuestion1;
class Program
{
static void Main(string[] args)
{
Furniture F = new Furniture("Chair", 1f, 2f, 3f);
F.Name = "Office chair"; // doesn't work, as expected
F.Position = new MyVector(5f, 6f, 7f); // doesn't work, as expected
F.Position.x = 5f; // works, unfortunately
F.Position.y = 6f; // works, unfortunately
F.Position.z = 7f; // works, unfortunately
}
}
Question
How to make it impossible to change the furniture's position, without making the coordinates of MyVector private and, thus, inaccesible? I want to have encapsulation, by only letting Furniture members access the position, but MyVector will become useless in other places if its values can't be changed.
A couple of points to make here:
By design you chose to make the fields public which means they are readily accessible from other classes. They are not private which is what the title implies. To force them to be read only use the readonly keyword
public class MyVector
{
public readonly float x;
public readonly float y;
public readonly float z;
public MyVector(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
Typically you won't expose the fields but instead use properties with getters defined only.
public class MyVector
{
private readonly float x;
private readonly float y;
private readonly float z;
public MyVector(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
public float X { get => x; }
public float Y { get => y; }
public float Z { get => z; }
}
Furthermore, you can simplify things using auto-properties
public class MyVector
{
public MyVector(float x, float y, float z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public float X { get; }
public float Y { get; }
public float Z { get; }
}
Finially, it recommended for value semantics where (x,y,z) will always go together to use struct declarations.
public readonly struct MyVector
{
public MyVector(float x, float y, float z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public float X { get; }
public float Y { get; }
public float Z { get; }
}
As a side note, if you try to modify the contents of a struct exposed by a property, the C# is going to complain.
Consider this code
public struct MyVector
{
public float x;
public float y;
public float z;
public MyVector(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
public class Movable
{
public Movable(MyVector position)
{
Position = position;
}
public MyVector Position { get; }
}
So even with by design allowing the contents of MyVector to be mutable (change), the compiler is going to stop you. This is because with struct types you have local copies of the data everywhere and by writing Position.x = 10f you would have modified a local copy of Position that exists in the scope where this is called, and not modified the original data.
In the question MyVector is a class and so Position.x = 10f modifies the original data and as stated this is undesirable behavior, so follow the steps above to disallow this behavior.
To make MyVector work well with other classes I often add the following functionality to such deflations. I add support for .ToString() with formatting and I add support for .Equals() (and == for structures) in order to be to write code like this:
static void Main(string[] args)
{
var pos = new MyVector(1f, 1/2f, 1/3f);
var m = new Movable(pos);
if (m.Position == pos)
{
Console.WriteLine($"{m.Position:f2}");
// (1.00,0.50,0.33)
}
}
Notice the formatting with 2 decimals and the equality check.
here is the complete code that allows this for your reference
MyVector.cs
public readonly struct MyVector : IEquatable<MyVector>, IFormattable
{
public MyVector(float x, float y, float z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public float X { get; }
public float Y { get; }
public float Z { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(MyVector)</code></returns>
public override bool Equals(object obj)
{
if (obj is MyVector other)
{
return Equals(other);
}
return false;
}
public static bool operator ==(MyVector target, MyVector other) { return target.Equals(other); }
public static bool operator !=(MyVector target, MyVector other) { return !(target == other); }
/// <summary>
/// Checks for equality among <see cref="MyVector"/> classes
/// </summary>
/// <param name="other">The other <see cref="MyVector"/> to compare it to</param>
/// <returns>True if equal</returns>
public bool Equals(MyVector other)
{
return X.Equals(other.X)
&& Y.Equals(other.Y)
&& Z.Equals(other.Z);
}
/// <summary>
/// Calculates the hash code for the <see cref="MyVector"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295) * hc + X.GetHashCode();
hc = (-1521134295) * hc + Y.GetHashCode();
hc = (-1521134295) * hc + Z.GetHashCode();
return hc;
}
}
#endregion
#region Formatting
public override string ToString() => ToString("g");
public string ToString(string formatting) => ToString(formatting, null);
public string ToString(string format, IFormatProvider provider)
{
return $"({X.ToString(format, provider)},{Y.ToString(format, provider)},{Z.ToString(format, provider)})";
}
#endregion
}
The problem with using a private setter for an object is that it only prevents you from replacing the object entirely. As it's not an immutable object, you can still access its properties change them, as you have found.
You could define an IMyVector interface with get only properties, have MyVector implement it, and then use the interface for your public Position property.
public interface IMyVector
{
float x {get;}
...
}
public class MyVector : IMyVector
{
...
}
public class Furniture : IMovable
{
public string Name { get; private set; }
public IMyVector Position { get; private set; }
...
Another design possibility is to declare IMyReadOnlyVector interface and expose it whenever we don't want to allow change vectors:
public interface IMyReadOnlyVector {
float x { get; }
float y { get; }
float z { get; }
}
public interface IMyVector : IMyReadOnlyVector {
float x { get; set; }
float y { get; set; }
float z { get; set; }
}
Then you implement MyVector:
public class MyVector : IMyVector {
public MyVector(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public float x { get; set; }
public float y { get; set; }
public float z { get; set; }
}
Now, time for the trick: IMovable uses IMyReadOnlyVector interface: we let user see Position but not allow to change it.
public interface IMovable {
string Name { get; }
// User can see position, but not allowed to change it
IMyReadOnlyVector Position { get; }
}
public class Furniture : IMovable {
// Private usage only: we don't want user explicitly change position
private MyVector m_Position;
public string Name { get; private set; }
// Public usage: user can't change vector's coordinates here
public IMyReadOnlyVector Position => m_Position;
public Furniture(string name, float x, float y, float z) {
this.Name = name;
this.m_Position = new MyVector(x, y, z);
}
// But we can change Position within the class
public void ShiftMe(int dx, int dy, int dz) {
m_Position.x += dx;
m_Position.y += dy;
m_Position.z += dz;
}
}
I do stuff where having contiguous data is required. Now with C# 10, we can do public readonly record struct.
I like having the automatic ToString feature that records have, among others, so having that done for me is nice.
As such, are the following equivalent?
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVector
{
public readonly float X;
public readonly float Y;
public readonly float Z;
public MyVector(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
versus the nicely condensed C# 10 version
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly record struct MyVectorRecord(float X, float Y, float Z)
{
}
Or are there any landmines I'm going to accidentally step on doing this? By which I mean are there any things being done under the hood by record that make what I've written above not do what I want with respect to contiguous packing? I can't have the record insert padding, spacing, or do anything weird.
I am not using a vector class with record structs and was using this for purposes of illustration. You can ignore things like "floating point equality comparisons" since I am only interested in whether I can pass this off to a library that is expecting a contiguous sequence of X/Y/Z's.
record isn't a new type, it's specific behavior applied to reference and now value types. The struct remains a struct. You can test this at sharplab.io, to see the code generated by the compiler in each case.
A record uses properties though, not raw fields, so you can only compare structs with properties to record structs. That's the important difference
This struct:
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVectorRecord2
{
public float X {get;}
public float Y {get;}
public float Z {get;}
public MyVectorRecord2(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
produces
[StructLayout(LayoutKind.Sequential, Pack = 4)]
[IsReadOnly]
public struct MyVectorRecord2
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly float <X>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly float <Y>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly float <Z>k__BackingField;
public float X
{
[CompilerGenerated]
get
{
return <X>k__BackingField;
}
}
public float Y
{
[CompilerGenerated]
get
{
return <Y>k__BackingField;
}
}
public float Z
{
[CompilerGenerated]
get
{
return <Z>k__BackingField;
}
}
public MyVectorRecord2(float x, float y, float z)
{
<X>k__BackingField = x;
<Y>k__BackingField = y;
<Z>k__BackingField = z;
}
}
While the record
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly record struct MyVectorRecord(float X, float Y, float Z)
{
}
produces:
[StructLayout(LayoutKind.Sequential, Pack = 4)]
[IsReadOnly]
public struct MyVectorRecord : IEquatable<MyVectorRecord>
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly float <X>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly float <Y>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly float <Z>k__BackingField;
public float X
{
[CompilerGenerated]
get
{
return <X>k__BackingField;
}
[CompilerGenerated]
init
{
<X>k__BackingField = value;
}
}
public float Y
{
[CompilerGenerated]
get
{
return <Y>k__BackingField;
}
[CompilerGenerated]
init
{
<Y>k__BackingField = value;
}
}
public float Z
{
[CompilerGenerated]
get
{
return <Z>k__BackingField;
}
[CompilerGenerated]
init
{
<Z>k__BackingField = value;
}
}
public MyVectorRecord(float X, float Y, float Z)
{
<X>k__BackingField = X;
<Y>k__BackingField = Y;
<Z>k__BackingField = Z;
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("MyVectorRecord");
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(' ');
}
stringBuilder.Append('}');
return stringBuilder.ToString();
}
private bool PrintMembers(StringBuilder builder)
{
builder.Append("X = ");
builder.Append(X.ToString());
builder.Append(", Y = ");
builder.Append(Y.ToString());
builder.Append(", Z = ");
builder.Append(Z.ToString());
return true;
}
public static bool operator !=(MyVectorRecord left, MyVectorRecord right)
{
return !(left == right);
}
public static bool operator ==(MyVectorRecord left, MyVectorRecord right)
{
return left.Equals(right);
}
public override int GetHashCode()
{
return (EqualityComparer<float>.Default.GetHashCode(<X>k__BackingField) * -1521134295 + EqualityComparer<float>.Default.GetHashCode(<Y>k__BackingField)) * -1521134295 + EqualityComparer<float>.Default.GetHashCode(<Z>k__BackingField);
}
public override bool Equals(object obj)
{
return obj is MyVectorRecord && Equals((MyVectorRecord)obj);
}
public bool Equals(MyVectorRecord other)
{
return EqualityComparer<float>.Default.Equals(<X>k__BackingField, other.<X>k__BackingField) && EqualityComparer<float>.Default.Equals(<Y>k__BackingField, other.<Y>k__BackingField) && EqualityComparer<float>.Default.Equals(<Z>k__BackingField, other.<Z>k__BackingField);
}
public void Deconstruct(out float X, out float Y, out float Z)
{
X = this.X;
Y = this.Y;
Z = this.Z;
}
}
Finally, this
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVector
{
public readonly float X;
public readonly float Y;
public readonly float Z;
public MyVector(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
Remains unchanged, apart from the IsReadOnly attribute.
[StructLayout(LayoutKind.Sequential, Pack = 4)]
[IsReadOnly]
public struct MyVector
{
public readonly float X;
public readonly float Y;
public readonly float Z;
public MyVector(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
The big difference is between structs with fields and structs with public properties. After that, a record struct contains only extra methods compared to a struct with properties.
I have written the code below, but i see that for to access the width and the length for the last child which is badRectangle is by overriding everything inhrerited from the Rectangle and shape class, which means i have to duplicate the input and i i had 6 or more levels of inheritance the code would kind of confuse and repeat a lot of things.
This code works correctly but is the correct way of dealing with inheritance in C#.
class Program
{
static void Main(string[] args)
{
badRectangle myRect = new badRectangle(true,"Rectangle",23.0,23);
Console.WriteLine("The Area of your Rectangle = " + myRect.getArea().ToString()
+ "\nAnd " + myRect.getStatus());
Console.ReadLine();
}
public abstract class shape
{
string type;
public abstract double getArea();
public shape(string type)
{
this.type = type;
}
}
public class rectangle : shape
{
double width, length;
public rectangle(string type, double width, double length):base(type)
{
this.width = width;
this.length = length;
}
public override double getArea()
{
return width * length;
}
}
public class badRectangle : rectangle
{
double width, length;
bool badOrNot = false;
public badRectangle(bool badOrNot,string type, double width, double length):base(type,width,length)
{
this.badOrNot = badOrNot;
this.width = width;
this.length = length;
}
public string getStatus()
{
string answer = "No, Rectangle is not bad";
if (badOrNot == true)
{
answer = "Yes, Rectangle is bad";
}
return answer;
}
public override double getArea()
{
return width * length;
}
}
}
This would be the "correct" or conventional way to do this in C#:
public abstract class Shape
{
public string Type { get; private set; }
public abstract double Area { get; }
public Shape(string type)
{
this.Type = type;
}
}
public class Rectangle : Shape
{
public double Length { get; private set; }
public double Width { get; private set; }
public Rectangle(string type, double width, double length)
: base(type)
{
this.Width = width;
this.Length = length;
}
public override double Area { get { return this.Width * this.Length; } }
}
public class BadRectangle : Rectangle
{
public bool BadOrNot { get; private set; } = false;
public BadRectangle(string type, double width, double length, bool badOrNot)
: base(type, width, length)
{
this.BadOrNot = badOrNot;
}
public string Status
{
get
{
string answer = "No, Rectangle is not bad";
if (this.BadOrNot == true)
{
answer = "Yes, Rectangle is bad";
}
return answer;
}
}
}
You don't need to set width and length in the derived classes again, just pass them to the constructor of the base class. If you need to access them in the derived class, make them protected. The getArea() doesn't have to be overridden if it does the same thing.
I need to further my knowledge of IInterface classes used with abstract classes. Whether this stuff is ever used have work requirements to learn a little more about it.
What I think an interface is (this works and calculates area for 3 items, Rectangle, Triangle, Circle using values provided):
static void Main(string[] args)
{
Rectangle r = new Rectangle(4, 8, "Rectangle");
Triangle t = new Triangle(4, 4, "Triangle");
Circle c = new Circle(3, "Circle");
r.DisplayArea();
Console.WriteLine();
t.DisplayArea();
Console.WriteLine();
c.DisplayArea();
Console.ReadKey();
}
Here is my abstract class. It looks like it deals with the name of what is being measured:
namespace DrawShapes
{
abstract class Shape
{
public string name;
public abstract void DisplayArea();
public Shape(string name)
{
this.name = name;
}
}
I'm not positively sure but wouldn't these be in the IInterface class and get set or called somehow? Definitely not an expert at this object oriented stuff.
public int Radius { get; set; }
public int Height { get; set; }
public int Width { get; set; }
Instead, I am hardcoding the parameters into the "function call":
static void Main(string[] args)
{
Rectangle r = new Rectangle(4, 8, "Rectangle");
Triangle t = new Triangle(4, 4, "Triangle");
Circle c = new Circle(3, "Circle");
}
I personally can't think of why or how I would use IInterface.
Just to be complete and maybe help someone who is looking for stuff like this, here are my classes to calculate areas.There are other SO answers to calculate areas, this question is about IInterface and abstract classes:
namespace DrawShapes
{
class Rectangle : Shape
{
public int length;
public int width;
public Rectangle(int length, int width, string name) : base(name)
{
//this.angles = angles;
this.length = length;
this.width = width;
}
public override void DisplayArea()
{
Console.Write(name + "--");
Console.Write(length * width);
}
}
class Triangle : Shape
{
// public int angles;
public int width;
public int height;
public Triangle(int width, int height, string name) : base(name)
{
//this.angles = angles;
this.width = width;
this.height = height;
}
public override void DisplayArea()
{
Console.Write(name + "--");
Console.Write((width * height) / 2);
}
}
class Circle : Shape
{
public int radius;
public Circle(int radius, string name) : base(name)
{
this.radius = radius;
}
public override void DisplayArea()
{
Console.Write(name + "--");
Console.Write(3.22 * radius * radius);
}
}
}