I want to make a function that takes a Position object and returns the latitude and longitude of this Position as a formated string.
But the problem is that I have 2 Position objects : one from Xamarin Forms and another one from a geolocation nugget.
Position from Xamarin forms:
public Position(double latitude, double longitude);
public double Latitude { get; }
public double Longitude { get; }
...
And Position from the geolocation nugget:
public Position();
public Position(Position position);
public double Latitude { get; set; }
public double Longitude { get; set; }
...
In order to have the two types working as one I made an interface :
interface IPosition
{
double Latitude
{
get;
set;
}
double Longitude
{
get;
set;
}
}
So my function should accept those two objects in parameter as follow :
public static string PositionToCoordonates<T>(T p)
{
return ((IPosition)p).Latitude.ToString().Replace(",", ".") + " ," + ((IPosition)p).Longitude.ToString().Replace(",", ".");
}
Unfortunatly it throws the error "System.InvalidCastException: Specified cast is not valid." at runtime.
What am I doing wrong ? I guess that I need some kind of dynamic cast but I'm not sure.
PositionToCoordonates shouldn't be generic. Making it generic is a way of saying that the parameter can be of any type. Your parameter can't be of any type, it needs to be an IPosition. Make the parameter of type IPosition, so that callers aren't allowed to pass in objects of another type (as they won't work), and you'll be able to see, from any compiler errors, what callers are passing in an object of the wrong type.
Note that once you change the parameter there will no longer be a reason for the method to be generic, nor will you need to be casting the parameter in the method body.
If both your Position classes implement IPosition, all you need is
public static string PositionToCoordonates(IPosition position)
There is no need for generics.
On the other hand, if those classes do not implement that interface (and that would be the case if you created it), you will have a bit of code duplication.
public static string PositionToCoordonates(Geolocation.Position position)
{
return PositionToCoordinates(position.Latitude, position.Longitude);
}
public static string PositionToCoordonates(Xamarin.Position position)
{
return PositionToCoordinates(position.Latitude, position.Longitude);
}
private static string PositionToCoordonates(double latitude, double longitude)
{
return string.Format(...);
}
As a clarification on the second part of my answer: In C#, classes have to declare they implement an interface, it is not enough to have the properties/methods defined on that interface.
So, in your example, position as IPosition will be null, and (IPosition) position will throw an exception.
For the above casts to work, Position has to be declared as
class Position : IPosition
{
...
}
Because both Positions are not implemented by you you can't just invent an interface to use it for casts imho. In this scenario I would probably handle this as follows:
void Main()
{
var position1 = new Position1() { Lat = 10, Lon = 5 };
var position2 = new Position1() { Lat = 12, Lon = 3 };
Console.WriteLine(GetLatLon(position1));
Console.WriteLine(GetLatLon(position2));
}
static string GetLatLon<T>(T input)
{
var position1 = input as Position1;
var position2 = input as Position2;
if (position1 != null)
{
return $"{position1.Lat}-{position1.Lon}";
}
if (position2 != null)
{
return $"{position2.Lat}-{position2.Lon}";
}
throw new ArgumentException(nameof(input));
}
class Position1
{
public double Foo { get; set ;}
public int Lat { get; set;}
public int Lon { get; set;}
}
class Position2
{
public int Lat { get; set; }
public int Lon { get; set; }
}
Dynamic seems to be too heavy for this scenario where only 2 possible types are involved. I don't know if the generic parameter is needed exactly but I left it in the hope, that boxing/unboxing will be avoided one time.
Related
I really struggle entitling this, but i'll try my best at explaining my point.
Say i have this :
List<IShape> Shapes = new List<IShape>();
public interface IShape {
dynamic shapeAttributes { get; set; }
};
public struct SquareAttributes {
float sizeOfSide;
};
public struct CircleAttributes {
float radius
};
public class Square : IShape {
SquareAttributes shapeAttributes { get; set; }
};
public class Circle : IShape {
CircleAttributes shapeAttributes { get; set; }
};
Shapes.Add(new Square());
Shapes.Add(new Circle());
How Do I make that situation work ? Here the "dynamic" keyword in IShape is not resolved when implemented in Square and Circle, but I'd still want to be able to define the right Type when implementing rather than using "dynamic" everywhere. Is there a right way to deal with this, with the ability re regroup all kind of Shapes in the same list? I hope this is clear.
I obviously simplified the whole thing to get straight to the point, but everything involved is far more complex and cannot really be fitted into a single large piece.
If your shapes attributes very different you can use System.Object as common type. But don't forget to check if you pass correct ShapeAttributes type to correct implementation of IShape, so I recommend to use set method instead of property setter:
Objects definition:
public interface IShape
{
object ShapeAttributes { get; }
Type ShapeAttributesType { get; }
void SetAttributes(object shapeAttributes);
}
public class Square : IShape
{
public object ShapeAttributes { get; private set; }
public Type ShapeAttributesType => typeof(SquareAttributes);
public void SetAttributes(object shapeAttributes)
{
// Check if passed correct type
if (shapeAttributes.GetType() != ShapeAttributesType)
throw new ArgumentException($"Argument type must be {ShapeAttributesType.FullName}", nameof(shapeAttributes));
ShapeAttributes = shapeAttributes;
}
}
public class Circle : IShape
{
public object ShapeAttributes { get; private set; }
public Type ShapeAttributesType => typeof(CircleAttributes);
public void SetAttributes(object shapeAttributes)
{
// Check if passed correct type
if (shapeAttributes.GetType() != ShapeAttributesType)
throw new ArgumentException($"Argument type must be {ShapeAttributesType.FullName}", nameof(shapeAttributes));
ShapeAttributes = shapeAttributes;
}
}
public struct SquareAttributes
{
public float SizeOfSide { get; set; }
}
public struct CircleAttributes
{
public float Radius { get; set; }
}
Usage example:
List<IShape> shapes = new List<IShape>();
var square = new Square();
square.SetAttributes(new SquareAttributes()
{
SizeOfSide = 4.1f
});
var circle = new Circle();
circle.SetAttributes(new CircleAttributes()
{
Radius = 2.12f
});
shapes.Add(square);
shapes.Add(circle);
foreach (var shape in shapes)
{
//Cast ShapeAttributes based on owner class type
switch (shape)
{
case Square s:
var size = ((SquareAttributes)s.ShapeAttributes).SizeOfSide;
Console.WriteLine($"Square.ShapeAttributes.SizeOfSide = {size}");
break;
case Circle c:
var radius = ((CircleAttributes)c.ShapeAttributes).Radius;
Console.WriteLine($"Circle.ShapeAttributes.Radius = {radius}");
break;
}
}
I recently came across a piece of code at work that has a repeating if-else condition that checks on an enum called OperationType :
public enum OperationType
{ A, B }
Right now the class's job is to run an operation either on device A or on device B, while reading from a SharedDevice and store some values basically for an X,Y plot. We record the characteristics of the SharedDevice in the function of DeviceA or DeviceB. The problem is that we need to iterate over a list of different parameters and send them to the SharedDevice. This list is different for device A and for device B.
Device class:
public class Device
{
public double CurrentValue { get; }
public DeviceParameters Parameters { get; set; }
}
And here is the class responsible for executing this operation:
public class MyOperationExecuter
{
public Device SharedDevice { get; }
public Device DeviceA { get; }
public Device DeviceB { get; }
public List<DeviceParameters> ParametersA { get; }
public List<DeviceParameters> ParametersB { get; }
public List<double> XValuesOfA { get; }
public List<double> YValuesOfA { get; }
public List<double> XValuesOfB { get; }
public List<double> YValuesOfB { get; }
public void DoMyOperation(OperationType operationType)
{
List<DeviceParameters> changingDeviceParameters;
if (operationType == OperationType.A)
{
changingDeviceParameters = ParametersA;
}
else
{
changingDeviceParameters = ParametersB;
}
if (operationType == OperationType.A)
{
XValuesOfA.Clear();
YValuesOfA.Clear();
}
else
{
XValuesOfB.Clear();
YValuesOfB.Clear();
}
foreach (var parameters in changingDeviceParameters)
{
// set the device parameters
SharedDevice.Parameters = parameters;
// retrieve the device readings and store the values in the correct dataprovider
if (operationType == OperationType.A)
{
XValuesOfA.Add(DeviceA.CurrentValue);
YValuesOfA.Add(SharedDevice.CurrentValue));
}
else
{
XValuesOfB.Add(DeviceB.CurrentValue);
YValuesOfB.Add(SharedDevice.CurrentValue);
}
}
// save updated x,y data
Save();
}
}
As you can see there is a repeating if statement which is not very future proof, since we have to check for the enum in every single step. Also we might need to add an C-type device which would result in an ever growing switch statement. We might also need to execute operations on both A and B. How should I refactor this operation so I can keep extending it without this always repeating if-else logic?
A fairly simple way would be to declare a variable representing A or B:
var XValues = operationType == OperationType.A ? XValuesOfA : XValuesOfB;
then you can just use XValues. Do the same for DeviceA. If you have more operations you could use a switch expression.
A neater solution would be to make separate objects containing everything needed for A or B, so your class could simply check the operation type and then delegate all the work to respective object. I.e.
public class MyDevice
{
public Device SharedDevice { get; }
public Device Device { get; }
public List<DeviceParameters> Parameters { get; }
public List<double> XValuesOf { get; }
public List<double> YValuesOf { get; }
public void DoMyOperation()
{
...
}
}
I would also recommend using a single list containing both X and Y values, something like a Vector2. I find this easier to use, and helps avoid repeating code.
Without changing class fields/properties I'd go with new method:
private void SetParameters(List<DeviceParameters> parameters, List<double> xValues, List<double> yValues, Device device)
{
xValues.Clear();
yValues.Clear();
foreach(var parameter in parameters)
{
SharedDevice.Parameters = parameter;
xValues.Add(device.CurrentValue);
yValues.Add(SharedDevice.CurrentValue);
}
}
And then in DoMyOperation it's enough to:
if (operationType == OperationType.A)
{
SetParameter(ParametersA, XValuesOfA, YValuesOfA, DeviceA);
}
else
{
SetParameter(ParametersB, XValuesOfB, YValuesOfB, DeviceB);
}
You should add new class. Which will be used to define device type specific properties.
A class like this;
public class MyDeviceValues
{
public MyDeviceValues(List<DeviceParameters> parameters, List<double> xValuesOf, List<double> yValuesOf)
{
Parameters = parameters;
XValues = xValuesOf;
YValues = yValuesOf;
}
public List<DeviceParameters> Parameters { get; }
public List<double> XValues { get; }
public List<double> YValues { get; }
}
So, you can have a generic DoMyOperation function. It will be like this:
public void DoMyOperation(MyDeviceValues myDeviceValues)
{
var changingDeviceParameters = myDeviceValues.Parameters;
myDeviceValues.XValues.Clear();
myDeviceValues.YValues.Clear();
foreach (var parameters in changingDeviceParameters)
{
// set the device parameters
SharedDevice.Parameters = parameters;
// retrieve the device readings and store the values in the correct dataprovider
myDeviceValues.XValues.Add(DeviceA.CurrentValue);
myDeviceValues.YValues.Add(SharedDevice.CurrentValue);
}
// save updated x,y data
Save();
}
Here is the refactored version of the whole code you pasted:
https://dotnetfiddle.net/dLyJl9
I've created a class that represent a component. This component has a width,height,x-Coordinate,y-Coordinate, etc. When I manipulate the width,height,x, and y, I want to keep the logic within the class. But there is an interface object within the Component Class that has similar values. This interface can be used to talk to different types of CAD software. The Shape interface can be null though.
So my question is what would be the best approach for this? In the example below, when I change "Y", should I check for null in the shape interface? Or maybe the Component Class has event handlers and the Shape Interface should register to them. So what would be best practice for designing this approach and what would give the best performance?
Appreciate it!
public class Component
{
private double _y;
public IShape Shape { get; set; }
public string Name { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double X { get; set; }
public double Y
{
get => _y;
set
{
_y = value;
if (Shape != null) Shape.Y = value;
}
}
public void Update_Shape()
{
//used to update the Shape Interface after it is assigned
}
}
public interface IShape
{
string Name { get; set; }
double Width { get; set; }
double Height { get; set; }
double X { get; set; }
double Y { get; set; }
}
UPDATE: To give more details, my interface will be able to talk to Microsoft Visio, and AutoCad. They are only meant to be used as a visual representation of the data, the are not in control of how many shapes, or where they are positioned. So in my application, the user can move, or change width/height within the application. If they have Visio open at the time, I want it to update Visio shapes as well. If it isn't open, then it doesn't matter(it will end up being updated later on). Same goes for AutoCad.
The best practice in this situation depends on what your design goals are.
If you want to automatically update IShape and performance is critical then manually writing out your setters with a null check is going to give you both. Having an event that the IShape subscribes to causes you to have to invoke the event which is more expensive than checking null. And this has the benefit of keeping the mess inside the class as you only need to assign myComponent.X = 20;
Having an event has it's benefits. If you look up the Observer Pattern you can find lots of good reads on this. If you have more than one IShape that would subscribe to your Component, say from both Visio and AutoCad at the same time this would be the way to go.
Now in terms of performance, if you're update less than a few thousand components per second and you want cleaner code I would just call Update_Shape() when you want to synchronize the values. If you are assigning multiple values at the same time you can wrap them in an action that will automatically synchronize the values after it completes.
var c = new Component();
c.Shape = new Shape();
c.UpdateShapes(s => {
s.Height = 100;
s.Width = 100;
s.X = 5;
});
public class Component
{
public IShape Shape { get; set; }
public string Name { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double X { get; set; }
public double Y { get; set; }
public void UpdateShapes(Action<Component> update)
{
update(this);
SyncronizeShapes();
}
public void SyncronizeShapes()
{
if (Shape != null)
{
Shape.Name = Name;
Shape.Width = Width;
Shape.Height = Height;
Shape.X = X;
Shape.Y = Y;
}
}
}
I have a set of instance fields inherited from class G481Vars by object G481Var.
G481Vars G481Var = new G481Vars();
The values of the instance fields are assigned to through this function
private void AssignValuesG481()
{
HtmlInputText[] G481Inputs = new HtmlInputText[13] //Create an explicit array of type HtmlInputText to handle elements of input boxes on G481 tab.
{
G481Disp_Txt, G481IniVel_Txt, G481FinVel_Txt, G481Acc_Txt,
G481Time_Txt, G481Force_Txt, G481Mass_Txt, G481Weight_Txt,
G481Press_Txt, G481Dens_Txt, G481Energy_Txt, G481Area_Txt,
G481Vol_Txt
};
double[] G481List = new double[13] //Create an explicit array of type double that stores the instance fields of class G481Vars
{
G481Var.Disp, G481Var.IniVel, G481Var.FinVel, G481Var.Acc,
G481Var.Time, G481Var.Force, G481Var.Mass, G481Var.Weight,
G481Var.Press, G481Var.Dens, G481Var.Energy, G481Var.Area,
G481Var.Vol
};
for (int i = 0; i <= 12; i++) //Perform the iterative loop
{
if (G481Inputs[i].Value != "")
{
double.TryParse(G481Inputs[i].Value, out G481List[i]);
}
}
}
Where G481Vars is Defined as:
public class G481Vars
{
public double Disp { get; set; }
public double IniVel { get; set; }
public double FinVel { get; set; }
public double Acc { get; set; }
public double Time { get; set; }
public double Force { get; set; }
public double Mass { get; set; }
public double Weight { get; set; }
public double Press { get; set; }
public double Dens { get; set; }
public double Energy { get; set; }
public double Area { get; set; }
public double Vol { get; set; }
}
However when i try and access these instance fields from another function CalculateG481_Click They always return 0, even though they are assigned to before hand.
protected void CalculateG481_Click(object sender, EventArgs e)
{
AssignValuesG481();
TempInputDebugField.Value = Convert.ToString(G481Var.Disp); //This always returns 0 in the field, even though <>0 was put into the disp input field and assignvariables run.
}
When I put the TempInputDebugField code into the AssignValuesG481 function it returns the correct value. Any ideas on what is going on with the instance field?
Thanks for your help.
It seems like you think that setting the value of an element of G481List will forward that value on to the corresponding property of G481Var that was used to initialize the array. That is not true. all it does is change the values within the array.
You'll need to set the values of the instance explicitly. You could use reflection to set the properties dynamically, but with only 13 properties it would be much safer and cleaner to just set them explicitly:
G481Var.Disp = double.Parse(G481Inputs[0].Value)
G481Var.IniVel = double.Parse(G481Inputs[1].Value)
G481Var.FinVel = double.Parse(G481Inputs[2].Value)
G481Var.Acc = double.Parse(G481Inputs[3].Value)
G481Var.Time = double.Parse(G481Inputs[4].Value)
G481Var.Force = double.Parse(G481Inputs[5].Value)
G481Var.Mass = double.Parse(G481Inputs[7].Value)
G481Var.Weight = double.Parse(G481Inputs[8].Value)
G481Var.Press = double.Parse(G481Inputs[9].Value)
G481Var.Dens = double.Parse(G481Inputs[10].Value)
G481Var.Energy = double.Parse(G481Inputs[11].Value)
G481Var.Area = double.Parse(G481Inputs[12].Value)
G481Var.Vol = double.Parse(G481Inputs[13].Value)
From there you can use TryParse to better handle bad values, you can try using reflection to reduce duplicate code (at the expense of compile-time safety), etc. The point is to get something that works, then find ways to make it better. You can always go back to less "elegant" code if you get tired or stuck trying to refactor it.
Try this :
for (int i = 0; i <= 12; i++) //Perform the iterative loop
{
double val;
if (G481Inputs[i].Value != "")
{
double.TryParse(G481Inputs[i].Value, out val);
G481List[i] = val;
}
}
double is a valuetype, so when you parse the strings the values are stored only in the array. You will have to assign this values to G481Var properties:
double value;
if (double.TryParse(G481Disp_Txt.Value, out value)
G481Var.Disp = value;
Do this for each property and should works fine
I have some different data types that i need to do something with in a function. Those data needs to be processed in the function and returned as an object i believe it is called.
This is some not tested code i just wrote here, but i think it displays what im trying to do .. I hope you guys can help me out how to do it.
private void Button_Click(object sender, RoutedEventArgs e)
{
// Here im calling the function which returns data to the object
object thoseProcessedData = SomeTestObject(5, "ABC", SomeOtherThing);
// When returned i want to be able to use the different data like so.
string useItLikeThis = thoseProcessedData.newString;
int numbersLikeThis = thoseProcessedData.newNumber;
}
public object SomeTestObject(int numbers, string letters, AnotherType anothertype)
{
string newString = letters.Substring(0,5);
int newNumber = numbers + 10;
AnotherType newType = anothertype.Something();
return processedData;
}
Please guys dont kill me, if this is a too stupid question. Im still very new to C# ..
If you dont get what im trying to do, please ask! Since my english is not the best i thought this way would be the best to show you what i want..
Create class which holds data you want to pass and return:
public class Data
{
public string Letters { get; set; }
public int Number { get; set; }
public AnotherType Thing { get; set; }
}
Pass it to method:
var data = new Data { Letters = "ABC", Number = 5, Thing = SomeOtherThing };
DoSomething(data);
// here data will have modified values
Thus class is a reference type, all changes to its members inside DoSomething method, will be reflected in your data object reference. So, changes can look like:
public void DoSomething(Data data)
{
data.Letters = data.Letters.Substring(0,5);
data.Number += 10;
data.Thing.Something();
}
Well, you are on the right track (apart from the use of the object keyword/class)!
The object class is the base class of every reference type in C#, it has 3 or 4 functions, and no properties. You will very rarely directly use this class.
The simplest method to do what are you trying to accomplish what you want is to use a Tuple.
This would look like:
public Tuple<string, int, AnotherType> SomeTestObject(
int numbers, string letters, AnotherType anothertype)
{
string newString = letters.Substring(0,5);
int newNumber = numbers + 10;
AnotherType newType = anothertype.Something();
return Tuple.Create(newString, newNumber, newType);
}
If, however, this is going to be used in other places, passed around, etc. you should create a separate object, populate it, and return it.
public MyDataClass SomeTestObject(
int numbers, string letters, AnotherType anothertype)
{
string newString = letters.Substring(0,5);
int newNumber = numbers + 10;
AnotherType newType = anothertype.Something();
return new MyDataClass(newString, newNumber, newType);
}
//Somewhere else, probably another file
public class MyDataClass
{
public string StringData {get; set;}
public int NumberData {get; set;}
public AnotherType ObjectData {get; set;}
public MyDataClass(string myString, int, myNumber, AnotherType myObject)
{
StringData = myString;
NumberData = myNumber;
ObjectData = myObject;
}
}
MSDN For:
Tuple
Object
Create a class to represent that data:
public class ProcessedData
{
public string NewString {get; set;}
public int NewNumber {get; set;}
public AnotherType NewType {get; set;}
}
then populate an instance of that class and return it:
private void Button_Click(object sender, RoutedEventArgs e)
{
// Here im calling the function which returns data to the object
ProcessedData thoseProcessedData = SomeTestObject(5, "ABC", SomeOtherThing);
// now you can access those properties
string useItLikeThis = thoseProcessedData.NewString;
int numbersLikeThis = thoseProcessedData.NewNumber;
}
public ProcessedData SomeTestObject(int numbers, string letters, AnotherType anothertype)
{
ProcessedData processedData = new ProcessedData();
processedData.newString = letters.Substring(0,5);
processedData.newNumber = numbers + 10;
processedData.newType = anothertype.Something();
return processedData;
}
There are mechanisms (anonymous types, dynamic) that would make it possible to dynamically "find" properties at run-time, but defining a class and statically typing the return type is by far safer.
Firstly, your English is fine. Don't worry about that :)
Secondly, what you want to do is just create a class that has those properties on it.
class YourClass {
public string NewString { get; set; }
public int NewNumber { get; set; }
}
Then return an instance of this out of your method:
return new YourClass() {
NewString = letters.Substring(0, 5),
NewNumber = numbers + 10
};
For this you can create a simple class.
public class Data
{
public string NewString { get; set; }
public int NewNumber { get; set; }
}
Then you can return it from a method.
Data ReadData()
{
return new Data {
NewString = CalculateNewString(),
NewNumber = CalclulateNewNumber()
};
}
When you need to return more than one value, you need to create your own class. A class (among other things) encapsulates or "packages together" one or more pieces of data. Here is an example:
public class MyCustomClass {
public int MyCustomInt { get; set; }
public string MyCustomString { get; set; }
public bool MyCustomYesNo { get; set; }
}
This class contains three properties. Properties contain data that can be read from (get) or written to (set). You can now write a function that returns an instance of this property:
public MyCustomClass MyFunction()
{
return new MyCustomClass() {
MyCustomInt = 15, MyCustomString = "Hello World!",
MyCustomYesNo = true
};
}
This function will create a new instance of our MyCustomClass and fill each property with values. And now you can call it like this:
MyCustomClass myVar = MyFunction();
int myInt = myVar.MyCustomInt; // Contains 15
string myString = myVar.MyCustomString; // Contains "Hello World!"
bool myYesNo = myVar.MyCustomYesNo; // Contains true
Now of course, your function can do anything it wishes. I was just providing an example.
Hope this makes sense!