I have problems with the encapsulation, and I don't where the problem is. Why can the line be altered after it has been created? This tells me something is wrong in my "line-class" and needs to be encapsulated. Advise would be much appreciated.
When calling "pa.X = 4" and "startpos.Y = 7" this should not change the line for me, but it does. I expect that all the lines are unchanged when the program has finished.
Dotclass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dot
{
class Dot
{
private int x;
private int y;
public Dot()
{
this.X = 0;
this.Y = 0;
}
public Dot(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X
{
get
{ return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
}
}
Lineclass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Dot
{
class Line
{
private Dot startdot;
private Dot enddot;
private double length;
public Line(Dot pa, Dot pb)
{
this.startdot = pa;
this.enddot = pb;
}
public double Size()
{
double a = (double)(enddot.X - startdot.X);
double b = (double)(enddot.Y - startdot.Y);
return length = Math.Sqrt(a * a + b * b);
}
public Dot Position()
{
return startdot;
}
}
}
Main:
using System;
namespace Dot
{
class Program
{
public static void Main()
{
Dot pa = new Dot();
Dot pb = new Dot(-10, -10);
Console.WriteLine("Dot pa, position = (" + pa.X + ", " + pa.Y + ")");
Console.WriteLine("Dot pb, position = (" + pb.X + ", " + pb.Y + ")");
Line line = new Line(pa, pb);
Print("Run 1 off line", line);
pa.X = 4;
Print("Run 2 off line", line);
Dot startpos = line.Position();
startpos.Y = 7;
Print("Run 3 off line", line);
}
private static void print(string text, Line line)
{
double length = line.Size();
Dot startPos = line.Position();
Console.WriteLine("\n" + text);
Console.WriteLine("Längd = {0 :f4} length", length);
Console.WriteLine("Position = ({0},{1})", startPos.X, startPos.Y);
Console.ReadLine();
}
}
}
Why can the line be altered after it has been created?
The reason is that class Dot is a reference type, and you want a value type, struct:
// please, notice "struct"
public struct Dot {
// you don't need separate fields, but properties
public int X {get; set;}
public int Y {get; set;}
public Dot(int x, int y) {
X = x;
Y = y;
}
}
....
EDIT: I suggest turning public Dot Position() into property as well:
class Line {
...
public Dot Position {
get {
return startdot;
}
set {
startdot = value;
}
}
}
and so you can "control the angles":
line.Position = new Dot(line.Position.X, 5);
Related
New to c# need help with the following error.
In class Grybai there is an error in Print case 'svoris' does not exist in current context. Print(A, ref n, Svoris); third argument 'Svoris' gives an error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace C
{
class Grybai
{
public string name;
private int Svoris;
public void Tipas(string nameType, int Weight) { name = nameType; Svoris = Weight; }
public string GetName() { return name; }
public int GetWeight() { return Svoris; }
Tried to do with GetWeight method, still nothing...
}
class Program
{
const string CFd = "..//..//Duom.txt";
const string CFr = "..//..//Rez.txt";
//Duomenu nuskaitymas is failo i masyva
static void Main(string[] args)
{
Grybai[] A = new Grybai[10]; //Sukuriam strukturu masyva
int n = 0;
Read(A, ref n);
Print(A, ref n, Svoris);
The name Svoris does not exist in current context, how to fix it?
}
static void Read(Grybai[] tarp, ref int n)
{
using (StreamReader reader = new StreamReader(CFd))
{
string line;
string[] parts;
if (File.Exists(CFr)) File.Delete(CFr);
while ((line = reader.ReadLine()) != null)
{
parts = line.Split(' ');
tarp[n] = new Grybai();
tarp[n].Tipas(parts[0], int.Parse(parts[1]));
n++;
}
}
}
static void Sort(Grybai[] tarpA, int n)
{
Grybai tarpB;
for (int j = 0; j < n; j++)
{
for (int i = 0; i < n - 1; i++)
{
if (tarpA[i].GetName()[0] > tarpA[i + 1].GetName()[0])
{
tarpB = tarpA[i];
tarpA[i] = tarpA[i + 1];
tarpA[i + 1] = tarpB;
}
}
}
}
static void Print(Grybai[] tarp, int n, int svoris)
{
string top = "|-----------------------------------------------------------|\r\n" +
"| Surusiuoti duomenys |\r\n" +
"|-----------------------------------------------------------|\r\n" +
"|Pavadinimas |Tipas |Svoris |\r\n" +
"|-----------------------------------------------------------|";
In order to resolves argument error on 'Svoris', you can replace a line of code as below.
Old Code : Print(A, ref n, Svoris);
New Code : Print(A, ref n, A.GetWeight());
As per your code, GetWeight() returns value of Svoris. It serves the intended purpose.
private int Svoris;
You "Svoris" is a private class viarable in "Grybai" class. You can't just access it like that in the "Program" class.
I'm building a simple class that allows me to calculate the dimensions of the room for a class and I'm having trouble getting the code to work. When I run it these are the errors I am receiving.
/p1/room.cs(1,7): error CS0116: A namespace cannot directly contain members such as fields or methods
/p1/room.cs(48,19): warning CS0108: 'Room.GetType()' hides inherited member 'object.GetType()'. Use the new keyword if hiding was intended.
/p1/room.cs(1,1): error CS0246: The type or namespace name 'Using' could not be found (are you missing a using directive or an assembly reference?)
I did some research and found that it seems that most of the time the two above errors refer to either unmatched brackets, but after searching through my room.cs file, I was unable to find any. In comparing the headers to my files to other classes I've found I can't find any differences.
Here is my room.cs file
Using System;
namespace p1
{
public class Room
{
private string type;
private double length;
private double width;
private double height;
public Room()
{
type = "Default";
length = 0.0;
width = 0.0;
height = 0.0;
}
public Room(string t, double l, double w, double h)
{
type = t;
length = l;
width = w;
height = h;
}
public void SetType(string t)
{
type = t;
}
public void SetLength(double l)
{
length = l;
}
public void SetWidth(double w)
{
width = w;
}
public void SetHeight(double h)
{
height = h;
}
public string GetType()
{
return type;
}
public double GetLength()
{
return length;
}
public double GetWidth()
{
return width;
}
public double GetHeight()
{
return height;
}
public double GetArea()
{
return length*width;
}
public double GetVolume()
{
return length*width*height;
}
public void Display()
{
Console.WriteLine("Room Type: " + this.GetType());
Console.WriteLine("Room Length: " + this.GetLength());
Console.WriteLine("Room Width: " + this.GetWidth());
Console.WriteLine("Room Height: " + this.GetHeight());
Console.WriteLine("Room Area: " + this.GetArea().ToString("F 2") + " sq ft " );
Console.WriteLine("Room Volume: " + this.GetVolume().ToString("F 2") + " cu ft ");
}
}
}
I can also post the program.cs file if needed, but this was getting quite long and I didn't want it to be unreadable.
Correct syntax to use NameSpace should be using not Using
Replace Using System; with using System;
Use
public new string GetType()
{
return type;
}
in place of to get rid of warning "Use new keyword is hiding was intented"
public string GetType()
{
return type;
}
In addition to what vivek nuna already said, you should get used to C#'s concept of properties. This will make your code less verbose and avoids the specific problem of hiding GetType():
public class Room
{
public string Type { get; set; } = "Default"; // with C#6 property initialization
public double Length { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public Room() {} // no code here, Type is initalized, double is 0 by default
public Room(string t, double l, double w, double h)
{
Type = t;
Length = l;
Width = w;
Height = h;
}
public double GetArea()
{
return Length * Width;
}
public double GetVolume()
{
return Length * Width * Height;
}
public void Display()
{
Console.WriteLine("Room Type: " + Type);
Console.WriteLine("Room Length: " + Length);
Console.WriteLine("Room Width: " + Width);
Console.WriteLine("Room Height: " + Height);
Console.WriteLine("Room Area: " + GetArea().ToString("F 2") + " sq ft " );
Console.WriteLine("Room Volume: " + GetVolume().ToString("F 2") + " cu ft ");
}
}
From outside you can now simply access the properties:
Room r = new Room();
r.Height = 12;
Console.WriteLine(r.Height);
The compiler does all the work you did yourself in your code. It creates backing fields for each property and the getter and setter methods. You don't have to do this and can concentrate on the real work.
In Unity 3D, I am trying to build a Dictionary of PathNodes keyed by NodeCoordinates. I have overridden GetHashCode in NodeCoordinate and it should return a constant unique value. If I loop through the keys of the dictionary, the lookup works fine, but if I create a new NodeCoordinate with the coordinates of a PathNode that should exist, the lookup fails even though the hash codes are equal.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PathNode : MonoBehaviour {
public static Dictionary<NodeCoordinate, PathNode> pathNodes;
public PathNode left;
public PathNode right;
public PathNode forward;
public PathNode backward;
private NodeCoordinate coord;
void Awake()
{
if (PathNode.pathNodes == null)
{
PathNode.pathNodes = new Dictionary<NodeCoordinate, PathNode>();
}
NodeCoordinate coord = new NodeCoordinate(transform.position.x, transform.position.z);
this.coord = coord;
PathNode.pathNodes.Add(coord, this);
NodeCoordinate leftChord = new NodeCoordinate(coord.x - 1, coord.z);
NodeCoordinate rightChord = new NodeCoordinate(coord.x + 1, coord.z);
NodeCoordinate forwardChord = new NodeCoordinate(coord.x, coord.z + 1);
NodeCoordinate backwardChord = new NodeCoordinate(coord.x, coord.z - 1);
if (PathNode.pathNodes.ContainsKey(leftChord))
{
this.left = PathNode.pathNodes[leftChord];
this.left.right = this;
}
if (PathNode.pathNodes.ContainsKey(rightChord))
{
this.right = PathNode.pathNodes[rightChord];
this.right.left = this;
}
if (PathNode.pathNodes.ContainsKey(forwardChord))
{
this.forward = PathNode.pathNodes[forwardChord];
this.forward.backward = this;
}
if (PathNode.pathNodes.ContainsKey(backwardChord))
{
this.backward = PathNode.pathNodes[backwardChord];
this.backward.forward = this;
}
}
private static bool debug = true;
void Update()
{
if (debug)
{
foreach (NodeCoordinate coord in PathNode.pathNodes.Keys)
{
Debug.Log(coord + " : " + PathNode.pathNodes[coord] + " : " + coord.GetHashCode());
}
foreach (PathNode node in PathNode.pathNodes.Values)
{
NodeCoordinate leftChord = new NodeCoordinate(node.coord.x - 1, node.coord.z);
PathNode leftNode;
Debug.Log("Left: " + leftChord + " : " + PathNode.pathNodes.TryGetValue(leftChord, out leftNode) + " : " + leftChord.GetHashCode());
}
debug = false;
}
}
}
public class NodeCoordinate
{
public float x;
public float z;
public NodeCoordinate(float x, float z)
{
this.x = x;
this.z = z;
}
public bool Equals(NodeCoordinate coord)
{
return (this.x == coord.x && this.z == coord.z);
}
public override int GetHashCode()
{
return string.Format("{0}x{1}", this.x, this.z).GetHashCode();
}
public override string ToString()
{
return "Coordinate: " + this.x + " x " + this.z;
}
}
This is the output from my little debug:
debug log
As you can see, when looping through the keys, the lookups with hashcodes 2137067561 and 1824497336 work, but when I instantiate a new NodeCoordinate and try to look it up, it has the same hashcode but the lookup fails. Any idea why this is happening? Thanks.
The problem is that your NodeCoordinate class doesn't define equality in a way that the dictionary would use. You have a method like this:
public bool Equals(NodeCoordinate coord)
... but you neither override IEquatable<NodeCoordinate> nor do you override Equals(object).
Personally I'd suggest doing both - and implementing a simpler hash code that doesn't require string formatting:
public sealed class NodeCoordinate : IEquatable<NodeCoordinate>
{
public float X { get; }
public float Z { get; }
public NodeCoordinate(float x, float z)
{
X = x;
Z = z;
}
public override Equals(object other) => Equals(other as NodeCoordinate);
public bool Equals(NodeCoordinate coord) =>
coord != null && this.X == coord.X && this.Z == coord.Z;
public override int GetHashCode()
{
int hash = 23;
hash = hash * 31 + X;
hash = hash * 31 + Z;
return hash;
}
public override string ToString() => $"Coodinate: {X} x {Z}";
}
(Note that I've also made it immutable and used properties instead of public fields. I've used C# 6 syntax for simplicity, but it wouldn't be hard to translate to C# 5 if necessary.)
So for some reason, when I add a IEqualityComparer with the exact same logic, it works.
Changed the declaration of the dictionary to this:
if (PathNode.pathNodes == null)
{
PathNode.pathNodes = new Dictionary<NodeCoordinate, PathNode>(new NodeCoordinateComparer());
}
Added this:
public class NodeCoordinateComparer : IEqualityComparer<NodeCoordinate>
{
public bool Equals(NodeCoordinate a, NodeCoordinate b)
{
return (a.x == b.x && a.z == b.z);
}
public int GetHashCode(NodeCoordinate coord)
{
return string.Format("{0}x{1}", coord.x, coord.z).GetHashCode();
}
}
Hey i just started by C# class 2 weeks ago so i am beginner programmer
and i am having trouble with my code. i have 2 classes, one of them is the test case that runs the program and the other has private variables. my variables color, NumOfWheels, StartingPoint, CurrentSpeed, and Mileage says property or indexer cannot be assigned to - it is read only when i try to build it. how do i fix this?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Homework1
{
class Car
{
private string color;
private int numOfWheels;
private int startingPoint;
private int mileage;
private int currentSpeed;
public Car()
{
Color = "";
NumOfWheels = 4;
StartingPoint = 100000;
CurrentSpeed = 0;
Mileage = 0;
}
public Car(string color, int numOfWheels, int startingPoint, int currentSpeed, int mileage)
{
Color = color;
NumOfWheels = numOfWheels;
StartingPoint = startingPoint;
CurrentSpeed = currentSpeed;
Mileage = mileage;
}
public virtual void setcolor(string color)
{
this.color = color;
}
public virtual void setnumOfWheels(int numOfWheels)
{
this.numOfWheels = numOfWheels;
}
public virtual string Color
{
get
{
return color;
}
}
public virtual double NumOfWheels
{
get
{
return numOfWheels;
}
}
public virtual int StartingPoint
{
get
{
return startingPoint;
}
}
public virtual int CurrentSpeed
{
get
{
return currentSpeed;
}
}
public virtual int Mileage
{
get
{
return mileage;
}
}
public override string ToString()
{
return (" color " + color + " numOfWheels" + numOfWheels + "startingPoint " + startingPoint + "mileage" + mileage + "current speed" + currentSpeed);
}
}
}
********************************************************************************
/// this is the test case that runs the program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication8
{
class CarTest
{
static void Main(string[] args)
{
Car myCar = new Car();
Console.WriteLine("*****************************");
Console.WriteLine("* *");
Console.WriteLine("* WELCOME TO CAR MANAGER *");
Console.WriteLine("* By <<my Name>> *");
Console.WriteLine("* *");
Console.WriteLine("*****************************");
Console.WriteLine("\nEnter the number of wheels of a car");
int numOfWheels = Console.Read();
myCar.setWheels(numOfWheels);
Console.WriteLine("Enter the color of the car");
String color = Console.ReadLine();
Console.WriteLine("Current mileage will be set to zero");
Console.WriteLine("The current starting point will be set to 100000");
Console.Write("The current status of your car \n{0:D} Wheels, \n{1}, \n{2:D} Miles and \nCAR POINT = {3:D}", myCar.getNumOfWheels,
myCar.getColor, myCar.getMileage, myCar.getStartingPoint);
Console.WriteLine("\nEnter the owner's name");
String name = Console.ReadLine();
Console.WriteLine("Enter the miles the car ran in this week");
int milesThisWeek = Console.ReadLine;
myCar.setMileage(Mileage);
Console.WriteLine("This car is owned by n{1}", name);
Console.WriteLine("===>The current status of your car:");
Console.WriteLine("Wheels: " + myCar.getWheels());
Console.WriteLine("Color: " + myCar.getColor());
Console.WriteLine("Current Mileage: " + myCar.getMileage());
Console.WriteLine("Starting Point: " + myCar.getStartingPoint());
Console.WriteLine("************ Thank you for using CAR MANAGER *************");
Console.WriteLine("----------------------------------------------------------");
Console.WriteLine("----------------------------------------------------------");
Console.WriteLine("Press ENTER to close console…….");
}
}
}
You're trying to set a property:
Color = "";
(among other places) But that property doesn't have a setter, only a getter:
public virtual string Color
{
get
{
return color;
}
}
In order to set the value of a property, it needs a setter:
public virtual string Color
{
get
{
return color;
}
set
{
color = value;
}
}
(repeat for your other properties as well)
It looks like you're trying to create Java-like setter methods:
public virtual void setcolor(string color)
{
this.color = color;
}
This works, and you can call those instead of trying to set the properties:
setColor("");
But it's not the expected convention in C#. The properties can manage the backing variables themselves. In fact, you can remove the backing variables entirely and use auto-implemented properties for simple values:
public virtual string Color { get; set; }
If you just need to hold a value, a simple property does that just fine. Methods are more for operations in code, not for getting/setting simple values. (Additionally, you wouldn't want to get into the habit of calling a lot of methods from a constructor. A constructor should really just build the state of the object and nothing else.)
What I am trying to do is get the number of right angled triangles between 1 and 20 on both sides.
Most of the logic is fine, but when I want to check for 3, 4 and 5 this is one triangle, while 4, 3 and 5 would not be valid as it 3, 4, 5 in a different order.
Here is the code that I have written for the problem area
public bool isAlreadyValidTriangle(int intAdj, int intOpp, List<Triangle> triangleList)
{
bool breakLoop = false;
Int32 length = triangleList.Count;
for (int index = 0; index < length && breakLoop != false; index++)
{
//This is to compare an existing adjacent that is stored in the list to the
//supplied opposite, this is to prebent the 3, 4, 5 and 4, 3, 5 issue
var response = triangleList.Find(r => r.IntAdjacent == intOpp);
if (response !=null)
{
//This is to compare an existing opposite that is stored in the list to the
//supplied adjacent, this is to prebent the 3, 4, 5 and 4, 3, 5 issue
var otherResponse = triangleList.Find(r => r.IntOpposite == intAdj);
if (otherResponse != null)
{
breakLoop = true;
}
}
}
return breakLoop;
}
Just in case anybody needs the Triangle code, here it is
public class Triangle
{
private int intAdjacent;
private int intOpposite;
private int intHypotenuse;
public Triangle(int intAdjacent, int intOpposite, int intHypotenuse)
{
this.intAdjacent = intAdjacent;
this.intOpposite = intOpposite;
this.intHypotenuse = intHypotenuse;
}
public int IntAdjacent
{
get { return intAdjacent; }
}
public int IntOpposite
{
get { return intOpposite; }
}
public int IntHypotenuse
{
get { return intHypotenuse; }
}
}
Could some one spot to see where I am making a mistake in the logic or have made an error in the code itself?
Keith
You can simplify this quite a lot like this:
public bool isAlreadyValidTriangle(int intAdj, int intOpp, List<Triangle> triangleList)
{
if(triangleList.Any(t => t.IntAdjacent == intAdj && t.IntOpposite == intOpp))
return true;
return triangleList.Any(t => t.IntAdjacent == intOpp && t.IntOpposite == intAdj);
}
It first looks for any matches where the passed in values are a match, then reverses the search if they don't. It's slightly different to your code in that it looks for both adjacent and opposite at the same time which is where you went wrong. Additionally, it uses Any which returns a boolean value if any item is found that matches.
Thinking about this further, I would change the function to make it an extension method like this:
public static bool isAlreadyValidTriangle(this List<Triangle> triangleList, int intAdj, int intOpp)
{
if(triangleList.Any(t => t.IntAdjacent == intAdj && t.IntOpposite == intOpp))
return true;
return triangleList.Any(t => t.IntAdjacent == intOpp && t.IntOpposite == intAdj);
}
This means you can call it with a little more readability:
List<Triangle> triangleList = new List<Triangle>();
... fill list with triangles ...
if(triangleList.isAlreadyValidTriangle(adjacent, opposite)
{
...
}
First of all thanks for the advice and help.
Here is the complete code from start to finish
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace ConsoleApplication1
{
public class Program
{
private static double doubleHypotenuse = 0;
private static int adjacent = 1;
private static int opposite = 1;
private static int limit = 200;
private static int count = 0;
public static void Main(string[] args)
{
TriangleLogic triLogic = new TriangleLogic();
List<Triangle> triangleList = new List<Triangle>();
List<Triangle> trianglePlus1 = new List<Triangle>();
while (adjacent < limit)
{
opposite = 1;
while (opposite < limit)
{
doubleHypotenuse = triLogic.intRightAngle(adjacent, opposite);
if (doubleHypotenuse % 1 == 0)
{
if (!triLogic.isAlreadyValidTriangle(adjacent, opposite, triangleList))
{
triangleList.Add(new Triangle(adjacent, opposite, (int)Convert.ToInt32(doubleHypotenuse)));
}
count++;
}
opposite++;
}
adjacent++;
}
Console.WriteLine("The following are integer triangles");
triangleList.ForEach(delegate(Triangle pytag)
{
if ((pytag.IntHypotenuse - pytag.IntOpposite) == 1)
{
trianglePlus1.Add(new Triangle(pytag.IntAdjacent, pytag.IntOpposite, pytag.IntHypotenuse));
}
Console.WriteLine(pytag.IntAdjacent + ", " + pytag.IntOpposite + " and " + pytag.IntHypotenuse);
});
Console.WriteLine("the number of squares is " + count);
Int32 length = triangleList.Count;
Console.WriteLine("the length of the list is " + length);
Console.WriteLine("");
Console.WriteLine("the List of triangles with the hypotenuse 1 ");
Console.WriteLine("more than the opposite");
trianglePlus1.ForEach(delegate(Triangle pytagPlus1)
{
Console.WriteLine(pytagPlus1.IntAdjacent + ", " + pytagPlus1.IntOpposite + " and " + pytagPlus1.IntHypotenuse);
});
Int32 lengthPlus1 = trianglePlus1.Count;
Console.WriteLine("the length of the list is " + lengthPlus1);
}
}
}
Here is the Triangle Class
public class Triangle
{
private int intAdjacent;
private int intOpposite;
private int intHypotenuse;
public Triangle(int intAdjacent, int intOpposite, int intHypotenuse)
{
this.intAdjacent = intAdjacent;
this.intOpposite = intOpposite;
this.intHypotenuse = intHypotenuse;
}
public int IntAdjacent
{
get { return intAdjacent; }
}
public int IntOpposite
{
get { return intOpposite; }
}
public int IntHypotenuse
{
get { return intHypotenuse; }
}
}
And finally the TriangleLogic class
public class TriangleLogic
{
private double squareAdjacent = 0;
private double squareOpposite = 0;
private double squareSum = 0;
public TriangleLogic()
{
}
public double intRightAngle(int intAdjacent, int intOpposite)
{
squareAdjacent = Math.Pow(Convert.ToDouble(intAdjacent), 2);
squareOpposite = Math.Pow(Convert.ToDouble(intOpposite), 2);
squareSum = squareAdjacent + squareOpposite;
return Math.Sqrt(squareSum);
}
public bool isAlreadyValidTriangle(int intAdj, int intOpp, List<Triangle> triangleList)
{
if (triangleList.Any(t => t.IntAdjacent == intAdj && t.IntOpposite == intOpp))
return true;
return triangleList.Any(t => t.IntAdjacent == intOpp && t.IntOpposite == intAdj);
}
}
Thanks again for the support