Access of private setter is not prohibited - c#

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;
}
}

Related

Cast changing generic type

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>

Do C#10’s readonly record structs guarantee the same size and alignment of fields as the explicit implementation?

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.

Utilizing C# inheritance correctly

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.

C# - defining hashset with custom key

I am using the HashSet and Dictionary in C# to implement a Graph structure. I have a problem with the uniqueness of HashSet elements when the HashSet key is a customized class. Here I have:
public class Point
{
public int x { get; set; }
public int y { get; set; }
}
public class Vertex
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
}
public class Edge
{
public Edge(Vertex to, Vertex from, double weight)
{
FromVertex = from;
ToVertex = to;
Weight = weight;
}
public Vertex FromVertex { get; private set; }
public Vertex ToVertex { get; private set; }
public double Weight { get; private set; }
}
public class Graph
{
public Graph()
{
_Vertexes = new HashSet<Vertex>();
_VertexEdgeMapping = new Dictionary<Vertex, LinkedList<Edge>>();
}
private HashSet<Vertex> _Vertexes;
private Dictionary<Vertex, LinkedList<Edge>> _VertexEdgeMapping;
}
The problem is that when I have same vertexes and I want to add them to the graph, they get duplicated. how can I define a way that the HashSet would understand the uniqueness of my vertexes?
Options:
Override Equals and GetHashCode in Vertex (and probably Point for simplicity), quite possibly implement IEquatable<T> as you go
Create your own implementation of IEqualityComparer<Vertex> and pass that to the constructor of the HashSet<Vertex>
The first option is likely to be the simplest, but I would strongly recommend that you make Point immutable first: mutable types (or types containing mutable types) don't make good hash keys. I'd probably make it a struct, too:
public struct Point : IEquatable<Point>
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
return 31 * x + 17 * y; // Or something like that
}
public override bool Equals(object obj)
{
return obj is Point && Equals((Point) obj);
}
public bool Equals(Point p)
{
return x == p.x && y == p.y;
}
// TODO: Consider overloading the == and != operators
}
... then override GetHashCode and Equals and implement IEquatable<> in Vertex too, e.g.
// Note: sealed to avoid oddities around equality and inheritance
public sealed class Vertex : IEquatable<Vertex>
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
public override int GetHashCode()
{
return VertexLabel.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Vertex);
}
public bool Equals(Vertex vertex)
{
return vertex != null && vertex.VertexLabel.Equals(VertexLabel);
}
}
Override GetHashCode() and Equals() methods of Vertex class.
Below is example, but you should use a bit better hashing algorithm than mine :)
public class Vertex
{
public Vertex(Point point)
{
VertexLabel = point;
}
public Point VertexLabel { get; private set; }
public override int GetHashCode()
{
return VertexLabel.X + VertexLabel.Y;
}
public override bool Equals(object obj)
{
//your logic for comparing Vertex
}
}
As others have said, override the GetHashCode() of the Vertex class.
Also override the .Equals method. Dictionary will use both GetHashCode and Equals to determine equality.
This is why Dictionary isn't replacing vertices. Vertices with the same coordinates are still fundamentally different as far as the Dictionary is concerned.
I won't pollute your question with yet another source code example as Jon and gzaxx have offered 2 very fine examples already.

C# classes and struct

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.

Categories