Error is
"A readonly field cannot be assigned to(...)"
I must return vector, which equal sum of two another vectors (vector and vector1)
ReadOnlyVector has readonly fields X and Y. How can I initialize them and return new ReadOnlyVector?
public class ReadOnlyVector
{
public readonly double X;
public readonly double Y;
public ReadOnlyVector(int x, int y)
{
X = x;
Y = y;
}
public ReadOnlyVector Add (ReadOnlyVector vector, ReadOnlyVector vector1)
{
return new ReadOnlyVector {X = vector.X + vector1.X, Y = vector.Y + vector1.Y}
}
}
Use the constructor. You're currently using object initializer syntax.
public ReadOnlyVector Add (ReadOnlyVector vector, ReadOnlyVector vector1)
{
return new ReadOnlyVector(vector.X + vector1.X, vector.Y + vector1.Y);
}
Related
This question already has answers here:
Changing the value of an element in a list of structs
(7 answers)
Closed 10 months ago.
In the following program, I am unable to modify individual list items:
public class Program
{
static void Main(string[] args)
{
List<Point2d> list = new List<Point2d>();
list.Add(new Point2d(0, 0));
list.Add(new Point2d(0, 1));
foreach (Point2d item in list)
{
item.Print();
}
Point2d p = list[0];
p.Set(-1, -1);
foreach (Point2d item in list)
{
item.Print();
}
Console.ReadKey();
}
}
Output:
(0,0) (0,1) (0,0) (0,1)
My expected output was:
(0,0) (0,1) (-1,-1) (0,1)
What am I doing incorrectly?
Relevant source code:
public struct Point2d : IEquatable<Point2d>
{
public double X { get; set; }
public double Y { get; set; }
#region constructor
public Point2d(double x, double y)
{
X = x;
Y = y;
}
#endregion
public void Print()
{
Console.Write("(");
Console.Write(X);
Console.Write(",");
Console.Write(Y);
Console.Write(") ");
}
public void Set(double x, double y)
{
X = x;
Y = y;
}
public double GetDistance(Point2d otherPoint)
{
return Math.Sqrt(GetSquaredDistance(otherPoint));
}
public double GetSquaredDistance(Point2d otherPoint)
{
return ((otherPoint.X - X) * (otherPoint.X - X))
+ ((otherPoint.Y - Y) * (otherPoint.Y - Y));
}
public Point2d GetTranslated(Point2d center)
{
return new Point2d(X + center.X, Y + center.Y);
}
#region override string ToString()
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("(" + X + " , " + Y + ")");
return sb.ToString();
}
#endregion
#region equality comparison implementations
public override bool Equals(object other)
{
if (!(other is Point2d)) return false;
return Equals((Point2d)other);
}
public bool Equals(Point2d other)
{
return X == other.X && Y == other.Y;
}
public override int GetHashCode()
{
return (int)Math.Round(Y * 31.0 + X, 0); // 31 = some prime number
}
public static bool operator ==(Point2d a1, Point2d a2)
{
return a1.Equals(a2);
}
public static bool operator !=(Point2d a1, Point2d a2)
{
return !a1.Equals(a2);
}
#endregion
}
Point2d is a struct so when you did Point2d p = list[0]; you made a totally separate copy of the object. Your set only changed the copy not the original, you either need to make Point2d a class or add a list[0] = p; after the set.
Bugs like this is why it is recommended to make structs immutable and have no Set methods.
This is my code I wrote a comment under the mistake. I am not allowed to do it in another way it should be two classes and it should be done in this way. If someone can help me i would appreciate this
Thank u
using System;
using MathLibrary;
namespace MathLibraryApp
{
class Program
{
static void Main(string[] args)
{
Vector v = new Vector();
Vector v1 = new Vector(4, 8, 12);
Vector v2 = new Vector(8,16,24);
Vector[] vectors = { v1, v2 };
Console.WriteLine(v.Add(vectors));
}
}
}
using System;
namespace MathLibrary
{
public class PointVectorBase
{
public PointVectorBase(double x=0 , double y=0 , double z=0 )
{
this.X = x;this.Y = y;this.Z = z;
}
protected virtual PointVectorBase CalculateSum(params Vector[] addends)
{
for (int i = 0; i < addends.Length; i++)
{
this.X = this.X + addends[i].X;
this.Y = this.Y + addends[i].Y;
this.Z = this.Z + addends[i].Z;
}
return this;
}
}
public class Vector : PointVectorBase
{
public Vector(double x = 0, double y = 0, double z = 0) : base(x, y, z){ }
public Vector Add(params Vector[] addends)
{
return this.CalculateSum(addends) ;
//Cannot implicitly convert type MathLibrary.PointVectorBase to MathLibrary.Vector. An explicit conversion exists (are you missing a cast?)
}
}
}
You can either cast the result like this:
public Vector Add(params Vector[] addends)
{
return this.CalculateSum(addends) As Vector;
}
This is dangerous though. Not all base vectors are vectors so you could have a null return. Same way as an animal is not always a cat in the public class cat: animal example.
Creating the implicit conversion is safer, though not always possible: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators
Your method CalculateSum returns value type PointVectorBase. Method Add in Vector class should return Vector.
Due to inheritance you can cast result of a CalculateSum to a Vector so it would be return this.CalculateSum(addends) as Vector;
In this case I wouldn't go for inheritance. You are only extending the base class with methods.
The problem on your CalculateSum is that you're returning this as a result. Which is a strange pattern. Either go for a void method which alters the current instance or return a new instance (so leave the current instance unmodified). I would go for the latter.
If your question is about inheritance, this is not a good example you gave.
But if you want an other way:
In your example I would go for extension methods. Also this is a nice case to use structs. By writing extension methods, you can extend the Vector3 with extra methods..
using System;
namespace MathLibrary
{
public struct Vector3
{
public double X;
public double Y;
public double Z;
public Vector3(double x=0 , double y=0 , double z=0 )
{
this.X = x;
this.Y = y;
this.Z = z;
}
public Vector3 CalculateSum(params Vector3[] addends)
{
var result = new Vector3();
for (int i = 0; i < addends.Length; i++)
{
result.X = result.X + addends[i].X;
result.Y = result.Y + addends[i].Y;
result.Z = result.Z + addends[i].Z;
}
return result;
}
}
public static class VectorExtensions
{
public static Vector3 Add(this Vector3 vector, params Vector3[] addends)
{
return vector.CalculateSum(addends);
// the add should actually add to the current vector,
// which makes it less readable.. calculate sum and add is almost the same.
return vector.CalculateSum(
new Vector3 [] { vector }
.Concat(addends)
.ToArray() );
}
}
}
The more your code has a functional approach the less strange things will happen.
I hope you have a nice day, so here is my problem: I'm trying to find the middle point of most populated positions (X/Y) on a map but i'm stuck and i can't find a good and effective way to do it.
To find this position i've access to an collection of entities (and these entities have a Position property (which is a Vector2D) and map size
public readonly struct Vector2D
{
private static readonly double Sqrt = Math.Sqrt(2);
private static readonly Random Random = new Random();
public static Vector2D Zero { get; } = new Vector2D();
public int X { get; }
public int Y { get; }
public Vector2D(int x, int y)
{
X = x;
Y = y;
}
public Vector2D GetDistanceTo(Vector2D vector2D) => new Vector2D(Math.Abs(vector2D.X - X), Math.Abs(vector2D.Y - Y));
public int GetDistance(Vector2D destination)
{
int x = Math.Abs(X - destination.X);
int y = Math.Abs(Y - destination.Y);
int min = Math.Min(x, y);
int max = Math.Max(x, y);
return (int)(min * Sqrt + max - min);
}
public bool IsInRange(Vector2D position, int range)
{
int dx = Math.Abs(X - position.X);
int dy = Math.Abs(Y - position.Y);
return dx <= range && dy <= range && dx + dy <= range + range / 2;
}
public override string ToString() => $"{X}/{Y}";
}
That's the only thing i've tried
public Vector2D FindMostPopulatedPosition()
{
IEnumerable<Vector2D> positions = Entities.Select(x => x.Position);
return new Vector2D((int)positions.Average(x => x.X), (int)positions.Average(x => x.Y));
}
Here is some example images
Red dot: All entities
Blue dot: The position i'm looking for
Thanks for reading (and for your help)
http://codepaste.net/i87t39
The error I get is "One of the parameters of a binary operator must be the containing type"
public class Vector3D<T>
{
public T x;
public T y;
public T z;
public Vector3D()
{
}
public Vector3D(T a, T b, T c)
{
x = a; y = b; z = c;
}
/*public Vector3D(double a, double b, double c)
{
x = a; y = b; z = c;
}*/
public override string ToString()
{
//return base.ToString();
return String.Format("({0} {1} {2})", x , y , z);
}
public Vector3D<double> operator+( Vector3D<double> right)
{
Vector3D<double> vd = new Vector3D<double>() { x = 0, y = 0, z = 0};
vd.x = left.x + right.x;
vd.y = left.y + right.y;
vd.z = left.z + right.z;
return vd;
}
}
If I copy the code in your link:
public class Vector3D<T>
{
public T x;
public T y;
public T z;
public Vector3D()
{
}
public Vector3D(T a, T b, T c)
{
x = a; y = b; z = c;
}
public override string ToString()
{
//return base.ToString();
return String.Format("({0} {1} {2})", x , y , z);
}
public Vector3D<double> operator+( Vector3D<double> right)
{
Vector3D<double> vd = new Vector3D<double>() { x = 0, y = 0, z = 0};
vd.x = left.x + right.x;
vd.y = left.y + right.y;
vd.z = left.z + right.z;
return vd;
}
}
The error which you have is in operator+, because the containing type is Exp<T>, not Exp<double>. You should change it. Also there is no definition of left in this method !
Your method should like something like that:
public static Vector3D<T> operator +(Vector3D<T> right)
{
Vector3D<T> vd = new Vector3D<T>();
vd.x = right.x;
vd.y = right.y;
vd.z = right.z;
return vd;
}
Without a lot of extra work, you're not going to be able to implement a fully general-purpose generic Vector3D<T> class complete with mathematical operators. There are no constraints that you can provide for the generic type that will at once allow T to be a built-in numeric type and at the same time provide math operators for T.
There are a variety of ways to deal with this, such as special-casing the type in the generic class (yuck!), requiring T to implement an interface (i.e. wrap a normal numeric type in a type that implements the interface), or making the type abstract and requiring specialized subclasses to implement the operators as named methods (one of which could even depend on an interface, while others based directly on numeric types would just implement them directly).
For example:
abstract class Vector3D<T>
{
public readonly T x;
public readonly T y;
public readonly T z;
public Vector3D() { }
public Vector3D(T x, T y, T z)
{
this.x = x;
this.y = y;
this.z = z;
}
public abstract Vector3D<T> Add(Vector3D<T> right);
}
class Vector3DDouble : Vector3D<double>
{
public Vector3DDouble() { }
public Vector3DDouble(double x, double y, double z)
: base(x, y, z)
{ }
public override Vector3D<double> Add(Vector3D<double> right)
{
return new Vector3DDouble(x + right.x, y + right.y, z + right.z);
}
}
Assuming for the moment you've somehow addressed that issue, let's look at your operator + overload. First, your code won't even compile. You have overloaded the unary + operator, because you only have one parameter right for the overload, but in the method body you assume a second parameter left which is undeclared.
A more sensible implementation might look like this:
public static Vector3D<T> operator+(Vector3D<T> left, Vector3D<T> right)
{
return left.Add(right);
}
Note: I'm assuming here you've solved the arithmetic issue by requiring implementers to provide the arithmetic operations via named method, e.g. Add() per my example above. Obviously the exact implementation here would depend on how you dealt with the general issue of doing math with T values.
I have an abstract class, Vector, which I would like to overload the operators +,-,*, etc.
I want any derived classes to be able to use these, and get an object back with the same type as the calling object.
I tried with generics, (as follows, in brief), but I couldn't find a legal way to do it:
public static T operator +<T>( T V1, T V2) where T : Vector
{
//some calculation
return new T(args);
}
I then tried to do it just using the base class:
public static Vector operator+(Vector V1, Vector V2)
{
if (V1.Dimension != V2.Dimension)
throw new VectorTypeException("Vector Dimensions Must Be Equal");
double[] ArgList = new double[V1.Dimension];
for (int i = 0; i < V1.Dimension; i++) { ArgList[i] = V1[i] + V2[i]; }
return (Vector)Activator.CreateInstance(V1.GetType(), new object[] { ArgList});
}
If this method is passed in two child objects, it should perform the operation on them, and return a new object of the same heritage.
The problem I ran into with this is that I cannot enforce that all such child classes must have a constructor with the appropriate signature, and I can't call the base constructor to make the object.
What are ways to either (a) Make either of these work, or (b) do this elegantly in another way?
You could declare instance-level abstract methods which your subclass can override:
public abstract class Vector
{
protected abstract Vector Add(Vector otherVector);
public static Vector operator +(Vector v1, Vector v2)
{
return v1.Add(v2);
}
}
public class SubVector : Vector
{
protected override Vector Add(Vector otherVector)
{
//do some SubVector addition
}
}
Might run into some issues especially with multiple subclasses (Will SubVector have to know how to add with SomeOtherSubVectorClass? What if you add ThirdVectorType class?) and perhaps handling null cases. Also, making sure that SubVector.Add behaves the same as SomeOtherSubVectorClass.Add when it comes to commutative operations.
EDIT: based on your other comments, you could so something like:
public class Vector2D : Vector
{
public double X { get; set; }
public double Y { get; set; }
protected override Vector Add(Vector otherVector)
{
Vector2D otherVector2D = otherVector as Vector2D;
if (otherVector2D != null)
return new Vector2D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y };
Vector3D otherVector3D = otherVector as Vector3D;
if (otherVector3D != null)
return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = otherVector3D.Z };
//handle other cases
}
}
public class Vector3D : Vector
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
protected override Vector Add(Vector otherVector)
{
Vector2D otherVector2D = otherVector as Vector2D;
if (otherVector2D != null)
return new Vector3D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y, Z = this.Z };
Vector3D otherVector3D = otherVector as Vector3D;
if (otherVector3D != null)
return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = this.Z + otherVector3D.Z };
//handle other cases
}
}
EDITx2:
Given your latest comment, perhaps your should just maintain an internal array/matrix and just do generic matrix math. Your subclasses can expose X/Y/Z property wrappers against the array indicies:
public class Vector
{
protected double[] Values;
public int Length { get { return Values.Length; } }
public static Vector operator +(Vector v1, Vector v2)
{
if (v1.Length != v2.Length)
{
throw new VectorTypeException("Vector Dimensions Must Be Equal");
}
else
{
//perform generic matrix addition/operation
double[] newValues = new double[v1.Length];
for (int i = 0; i < v1.Length; i++)
{
newValues[i] = v1.Values[i] + v2.Values[i];
}
//or use some factory/service to give you a Vector2D, Vector3D, or VectorND
return new Vector() { Values = newValues };
}
}
}
public class Vector2D : Vector
{
public double X
{
get { return Values[0]; }
set { Values[0] = value; }
}
public double Y
{
get { return Values[1]; }
set { Values[1] = value; }
}
}
public class Vector3D : Vector
{
public double X
{
get { return Values[0]; }
set { Values[0] = value; }
}
public double Y
{
get { return Values[1]; }
set { Values[1] = value; }
}
public double Z
{
get { return Values[2]; }
set { Values[2] = value; }
}
}
EDITx3: Based on your latest comment, I guess you could implement operator overloads on each subclass, do the shared logic in a static method (say in the base Vector class), and somewhere do a switch/case check to provide a specific subclass:
private static Vector Add(Vector v1, Vector v2)
{
if (v1.Length != v2.Length)
{
throw new VectorTypeException("Vector Dimensions Must Be Equal");
}
else
{
//perform generic matrix addition/operation
double[] newValues = new double[v1.Length];
for (int i = 0; i < v1.Length; i++)
{
newValues[i] = v1.Values[i] + v2.Values[i];
}
//or use some factory/service to give you a Vector2D, Vector3D, or VectorND
switch (newValues.Length)
{
case 1 :
return new Vector1D() { Values = newValues };
case 2 :
return new Vector2D() { Values = newValues };
case 3 :
return new Vector3D() { Values = newValues };
case 4 :
return new Vector4D() { Values = newValues };
//... and so on
default :
throw new DimensionOutOfRangeException("Do not support vectors greater than 10 dimensions");
//or you could just return the generic Vector which doesn't expose X,Y,Z values?
}
}
}
Then your subclasses would have:
public class Vector2D
{
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return (Vector2D)Add(v1, v2);
}
}
public class Vector3D
{
public static Vector3D operator +(Vector3D v1, Vector3D v2)
{
return (Vector3D)Add(v1, v2);
}
}
Some duplication, but I don't see a way around it off the top of my head to allow the compiler to do this:
Vector3 v1 = new Vector3(2, 2, 2);
Vector3 v2 = new Vector3(1, 1, 1);
var v3 = v1 + v2; //Vector3(3, 3, 3);
Console.WriteLine(v3.X + ", " + v3.Y + ", " + v3.Z);
or for other dimensions:
Vector2 v1 = new Vector2(2, 2);
Vector2 v2 = new Vector2(1, 1);
var v3 = v1 + v2; //Vector2(3, 3, 3);
Console.WriteLine(v3.X + ", " + v3.Y); // no "Z" property to output!
What about having an abstract method called Add() that operator+ just acts as a wrapper for? ie, "return v1.Add(v2)". This would also enable you to define interfaces which non-Vector classes can constrain their code to, enabling to perform math-like operations (since generic code can't see/touch operators like +, -, etc for any type).
The only constructor you can code with in a generic method is the default (ie, parameter-less) constructor, which you have to specify in the generic constraints for the method/type.
Five years later I had the exact same problem, only I was calling them Ntuples, not vectors. Here is what I did:
using System;
using System.Collections.Generic;
public class Ntuple{
/*parent class
has an array of coordinates
coordinate-wise addition method
greater or less than in dictionary order
*/
public List<double> Coords = new List<double>();
public int Dimension;
public Ntuple(List<double> Input){
Coords=Input;
Dimension=Input.Count;
}//instance constructor
public Ntuple(){
}//empty constructor, because something with the + overload?
public static Ntuple operator +(Ntuple t1, Ntuple t2)
{
//if dimensions don't match, throw error
List<double> temp = new List<double>();
for (int i=0; i<t1.Dimension; i++){
temp.Add(t1.Coords[i]+t2.Coords[i]);
}
Ntuple sum = new Ntuple(temp);
return sum;
}//operator overload +
public static bool operator >(Ntuple one, Ntuple other){
//dictionary order
for (int i=0; i<one.Dimension; i++){
if (one.Coords[i]>other.Coords[i]) {return true;}
}
return false;
}
public static bool operator <(Ntuple one, Ntuple other){
//dictionary order
for (int i=0; i<one.Dimension; i++){
if (one.Coords[i]<other.Coords[i]) {return true;}
}
return false;
}
}//ntuple parent class
public class OrderedPair: Ntuple{
/*
has additional method PolarCoords, &c
*/
public OrderedPair(List<double> Coords) : base(Coords){}
//instance constructor
public OrderedPair(Ntuple toCopy){
this.Coords=toCopy.Coords;
this.Dimension=toCopy.Dimension;
}
}//orderedpair
public class TestProgram{
public static void Main(){
List<double> oneCoords=new List<double>(){1,2};
List<double> otherCoords= new List<double>(){2,3};
OrderedPair one = new OrderedPair(oneCoords);
OrderedPair another = new OrderedPair(otherCoords);
OrderedPair sum1 = new OrderedPair(one + another);
Console.WriteLine(one.Coords[0].ToString()+one.Coords[1].ToString());
Console.WriteLine(sum1.Coords[0].ToString()+sum1.Coords[1].ToString());
bool test = one > another;
Console.WriteLine(test);
bool test2 = one < another;
Console.WriteLine(test2);
}
}
}//namespace ntuples