Here's typical class.
class Round
{
private int radius;
private bool Validate(int radius)
{
if (radius <= 0)
{
return false;
}
else
{
return true;
}
}
public int X { get; set;}
public int Y { get; set;}
public int Radius
{
get
{
return radius;
}
set
{
try
{
if(!Validate(value))
{
throw new ArgumentException();
}
radius = value;
}
catch (ArgumentException)
{
Console.WriteLine("ooops... something went wrong.");
return;
}
}
}
public Round (int X, int Y, int radius)
{
try
{
if (!Validate(radius))
{
throw new ArgumentException();
}
this.X = X;
this.Y = Y;
this.radius = radius;
}
catch (Exception)
{
Console.WriteLine("ooops... something went wrong.");
}
}
public double GetPerimeter()
{
return Math.PI * radius * 2;
}
}
class Program
{
static void Main(string[] args)
{
Round r = new Round(0,0,0);
Console.WriteLine(r.GetPerimeter());
}
}
As you can see, I send incorrect value to constructor that sends the value to validator. I can't understand what should I do to make constructor stop creating object ???.
The way to stop a constructor is to throw an exception.
You are doing that, but then you are also catching the exception. That way, the constructor will continue. Don't catch it.
if you don't want to throw exception in constructor, you could consider this method
// constructor
public Round (int X, int Y, int radius)
{
this.X = X;
this.Y = Y;
this.radius = radius;
}
// create instance
public static Round CreateInstance(int X, int Y, int radius)
{
if (!Validate(radius))
{
return null;
}
return new Round(X, Y, radius);
}
How to use:
// invalid should be null
Round invalid = Row.CreateInstance(1, 1, -1);
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>
I am following multiple tutorials and I don't understand all of the code, but basically, I'm instantiating a series of game objects along an L-System. Then I'm creating a Grid like this:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj is Point)
{
Point p = obj as Point;
return this.X == p.X && this.Y == p.Y;
}
return false;
}
public override int GetHashCode()
{
unchecked
{
int hash = 6949;
hash = hash * 7907 + X.GetHashCode();
hash = hash * 7907 + Y.GetHashCode();
return hash;
}
}
public override string ToString()
{
return "P(" + this.X + ", " + this.Y + ")";
}
}
public enum CellType
{
Empty,
Road,
Structure,
SpecialStructure,
None
}
public class Grid
{
private CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
private List<Point> _roadList = new List<Point>();
private List<Point> _specialStructure = new List<Point>();
private List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
// Adding index operator to our Grid class so that we can use grid[][] to access specific cell from our grid.
public CellType this[int i, int j]
{
get
{
return _grid[i, j];
}
set
{
if (value == CellType.Road)
{
_roadList.Add(new Point(i, j));
}
if (value == CellType.SpecialStructure)
{
_specialStructure.Add(new Point(i, j));
}
if (value == CellType.Structure)
{
_houseStructure.Add(new Point(i, j));
}
_grid[i, j] = value;
}
}
After the game objects are instantiated, I want to add each instantiated gameobject into into the grid and assign each of them a type. I have a script on a my gameobjects which basically stores the type as a string, and I know how to pass it as an enum. But how do I set each game object into the grid with the type, and point?
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;
}
}
in my case, I have list of list of points I want to discard the lists of duplicate points using linq in a similar way to how the distinct works in List of items usually.
How could I do it?
Here it is a code snippet to understand better my issue
var points = List<List<Point>>();
public struct Point: IEquatable<Point>
{
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
}
Thanks
First, actually implement IEquatable:
public struct Point: IEquatable<Point> {
public Point(int x, int y) {
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public bool Equals (Point other) =>
this.X == other.X && this.Y == other.Y;
}
Then create a custom equality comparer. That requires an equality logic, and a hash code generator. For the equality logic, use SequenceEqual, for the hash code generator, you'll have to play around with it, but here's an example via Jon Skeet. I used part of his logic below:
class ListPointComparer : IEqualityComparer<List<Point>> {
public bool Equals(List<Point> a, List<Point> b) => a.SequenceEqual(b);
public int GetHashCode(List<Point> list) {
int hash = 19;
foreach(var point in list)
hash = hash * 31 + point.GetHashCode();
return hash;
}
}
Now imagine points like this:
var pointsA = new List<Point> { new Point (1,1), new Point(2,2) };
var pointsB = new List<Point> { new Point (1,1), new Point(2,2) };
var pointsC = new List<Point> { new Point (3,3), new Point(4,4) };
var pointLists = new List<List<Point>> { pointsA, pointsB, pointsC };
Use your comparer class:
var results = pointLists.Distinct(new ListPointComparer());
// Outputs only 2 lists, with pointsA and pointsB combined.
You can use HashSet this class provide high-performance set operations. A set is a Collection that CONTAINS NO DUPLICATE elements, and whose elements are in no particular order
Example:
public struct Point
{
public HashSet<int> coordinateX;
public HashSet<int> coordinateY;
public Point(HashSet<int> a, HashSet<int> b)
{
coordinateX = a;
coordinateY = b;
}
}
static void Main(string[] args)
{
var set1 = new HashSet<int>() { 2, 3, 4, 6, 8 };
var set2 = new HashSet<int>() { 67, 31, 1, 3, 5 };
var points = new List<List<Point>>();
points.Add(new List<Point>() { new Point(set1, set2) });
//TODO
}
If you have code like this
public class Point : IEquatable<Point>
{
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public bool Equals(Point other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
//Check whether the products' properties are equal.
return X.Equals(other.X) && Y.Equals(other.Y);
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
int hashProductX = X == null ? 0 : X.GetHashCode();
//Get hash code for the Code field.
int hashProductY = Y == null ? 0 : Y.GetHashCode();
//Calculate the hash code for the product.
return hashProductX ^ hashProductY;
}
}
then this code would work
var distinct_points = points.Distinct();
assuming points is defined like this
List<Point> points;
you can also use
var distinct_points = points.SelectMany(x => x).Distinct();
if points is defined like this
var points = List<List<Point>>();
documentation this example was adapted from https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8
Linq Distinct can use an IEqualityComparer<>
You can implement a new class implementing that interface and then generate distinct lists.
Here is an implementation of a fully coded Point implementing IEquatable<>, and implemented IEqualityComparer<> and a Test class.
The test class does a 'simple' distinct on each list. If you need an more complex distinct, such as distinct points across all lists, post your functional requirements and I can see what i can do.
public struct Point : IEquatable<Point>
{
public Point(int x, int y) : this()
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public bool Equals(Point other)
{
if (other.X == X && other.Y == Y)
return true;
return false;
}
public override bool Equals(object obj)
{
if (obj != null && obj.GetType() == typeof(Point))
return Equals((Point)obj);
return base.Equals(obj);
}
public override int GetHashCode()
{
return HashCode.Combine(X, Y);
}
public int GetHashCode(Point obj)
{
return obj.GetHashCode();
}
}
public class PointComparer : IEqualityComparer<Point>
{
public bool Equals(Point x, Point y)
{
return x.Equals(y);
}
public int GetHashCode(Point obj)
{
return obj.GetHashCode();
}
}
public class Tester
{
public static List<List<Point>> Dist(List<List<Point>> points)
{
var results = new List<List<Point>>();
var comparer = new PointComparer();
foreach (var lst in points)
{
results.Add(lst.Distinct(comparer).ToList());
}
return results;
}
}
I have a serializable class named DataSource:
namespace GraphLib
{
public struct cPoint
{
public float x;
public float y;
}
[Serializable]
public class DataSource
{
public delegate String OnDrawXAxisLabelEvent(DataSource src, int idx);
public delegate String OnDrawYAxisLabelEvent(DataSource src, float value);
public OnDrawXAxisLabelEvent OnRenderXAxisLabel = null;
public OnDrawYAxisLabelEvent OnRenderYAxisLabel = null;
private cPoint[] samples = null;
private int length = 0;
private String name = String.Empty;
private int downSample = 1;
private Color color = Color.Black;
public float VisibleDataRange_X = 0;
public float DY = 0;
public float YD0 = -200;
public float YD1 = 200;
public float Cur_YD0 = -200;
public float Cur_YD1 = 200;
public float grid_distance_y = 200; // grid distance in units ( draw a horizontal line every 200 units )
public float off_Y = 0;
public float grid_off_y = 0;
public bool yFlip = true;
public bool Active = true;
private bool YAutoScaleGraph = false;
private bool XAutoScaleGraph = false;
public float XAutoScaleOffset = 100;
public float CurGraphHeight = 1.0f;
public float CurGraphWidth = 1.0f;
public float InitialGraphHeight = 0;
public float InitialGraphWidth = 0;
public bool AutoScaleY
{
get
{
return YAutoScaleGraph;
}
set
{
YAutoScaleGraph = value;
}
}
public bool AutoScaleX
{
get
{
return XAutoScaleGraph;
}
set
{
XAutoScaleGraph = value;
}
}
public cPoint[] Samples
{
get
{
return samples;
}
set
{
samples = value;
length = samples.Length;
}
}
public float XMin
{
get
{
float x_min = float.MaxValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.x < x_min) x_min=p.x;
}
}
return x_min;
}
}
public float XMax
{
get
{
float x_max = float.MinValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.x > x_max) x_max = p.x;
}
}
return x_max;
}
}
public float YMin
{
get
{
float y_min = float.MaxValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.y < y_min) y_min = p.y;
}
}
return y_min;
}
}
public float YMax
{
get
{
float y_max = float.MinValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.y > y_max) y_max = p.y;
}
}
return y_max;
}
}
public void SetDisplayRangeY(float y_start, float y_end)
{
YD0 = y_start;
YD1 = y_end;
}
public void SetGridDistanceY( float grid_dist_y_units)
{
grid_distance_y = grid_dist_y_units;
}
public void SetGridOriginY( float off_y)
{
grid_off_y = off_y;
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(string), "")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public String Name
{
get { return name; }
set { name = value; }
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(Color), "")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Color GraphColor
{
get { return color; }
set { color = value; }
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(int), "0")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Length
{
get { return length; }
set
{
length = value;
if (length != 0)
{
samples = new cPoint[length];
}
else
{
// length is 0
if (samples != null)
{
samples = null;
}
}
}
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(int), "1")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Downsampling
{
get { return downSample; }
set { downSample = value; }
}
}
}
and i want to serialize it in a form like this:
public partial class Form1 : Form
{
public GraphLib.PlotterDisplayEx display;
private void serialize()
{
System.IO.Stream TestFileStream = System.IO.File.Create(#"C:\Users\Public\Documents\test.txt");
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
serializer.Serialize(TestFileStream, display.DataSources[0]);
TestFileStream.Close();
}
not that DataSource class that i want to serialize in Form1, is one of the attributes in GraphLib.PlotterDisplayEx class
but when i run the program it gives me the following error:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Additional information: Type 'KTK.Form1' in Assembly 'KTK, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
UPDATE
I updated the code for DataSource class.now it's complete code guys.
You probably didn't show the complete code of the DataSource class. It directly or indirectly holds a reference to an object of type KTK.Form1.
This might be through an event to which the form is subscribed.
In this case you probably don't want to serialize it an should mark it as NonSerialized:
[field:NonSerialized]
public event ...;
Now that you updated the question. Change
public OnDrawXAxisLabelEvent OnRenderXAxisLabel = null;
public OnDrawYAxisLabelEvent OnRenderYAxisLabel = null;
to
[NonSerialized]
public OnDrawXAxisLabelEvent OnRenderXAxisLabel;
[NonSerialized]
public OnDrawYAxisLabelEvent OnRenderYAxisLabel;
The delegates may hold references to non-serializable classes.