Different types in C# Interface Implementation - c#

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

Related

Advice to get rid of repeating if statement in my class

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

Covariance, generic, UserControl

I have created a user control that contains an ObservableCollection<Something>. I learned that I cannot cast say ObservableCollection<Tiger> to ObservableCollection<Animal>. The solution I found was to add a helper class that handles all low level collection manipulation. My suspicion is that there is a more elegant solution and if so, maybe someone can point me into that direction.
See the code below that captures the problem and my solution. Zoo corresponds to the WPF UserControl. (Actually a zoo for one type od animal.) Ideally I would define it as Zoo<T> i.e. as a generic type but that would prevent me from using XAML. I need to define Animals as object in order assign to it.
class Program
{
public static void Main(string[] args)
{
Zoo zoo = new Zoo();
List<Tiger> tigers = new List<Tiger>() { new Tiger() };
zoo.Animals = tigers;
zoo.Helper = new TigerHelper(tigers);
Console.WriteLine(zoo.GetCount());
Console.ReadLine();
}
}
public class Animal { }
public class Tiger : Animal { }
public interface Helper { int GetCount(); }
public class TigerHelper : Helper
{
private List<Tiger> tigers;
public TigerHelper(List<Tiger> tigers) { this.tigers = tigers; }
public int GetCount() { return tigers.Count; }
}
public class Zoo
{
public object Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Helper.GetCount(); }
}
Rather than go all the way down to object, you can use IList. This gives you access to most of the features of the list, but without the generics. For example, you can still access the Count property:
public class Zoo
{
public IList Animals { get; set; }
public Helper Helper { get; set; }
public int GetCount() { return Animals.Count; }
}

Define a generic type constraint to be of the same type as the implementation

I wonder if it is possible to force constraint on interface or abstract class generic type to be the same as the concrete class that implements it specially for it.
Lets say we want to check a fitness of certain entity to task and make it comparable to others in their proficiency
abstract class Entity
{
public abstract int Fitness(); //Bigger the number - more fit the entity is
public int MoreFitThan(Entity other)
{
return Fitness().CompareTo(other.Fitness());
}
}
class Fish : Entity
{
public int swimSpeed { get; set; }
public override int Fitness()
{
return swimSpeed;
}
}
class Human : Entity
{
public int testPoints { get; set; }
public override int Fitness()
{
return testPoints;
}
}
But now we can compare fish's speed with human's test passing capability, which doesn't make sense.
static void Main()
{
Human human = new Human() {testPoints = 10};
Fish fish = new Fish() { swimSpeed = 20 };
fish.MoreFitThan(human);
}
So is there a general way make some kind of class or interface that would force it's children classes to implement only own type to own type comparison?
Like so we could only compare people with people and fish to fish, but without explicitly specifying the type of comparable entity?
You can force the type being passed to MoreFitThan to match the inheriting class by using generics in the following way.
abstract class Entity<T> where T : Entity<T>
{
public abstract int Fitness(); //Bigger the number - more fit the entity is
public int MoreFitThan(T other)
{
return Fitness().CompareTo(other.Fitness());
}
}
class Fish : Entity<Fish>
{
public int swimSpeed { get; set; }
public override int Fitness()
{
return swimSpeed;
}
}
class Human : Entity<Human>
{
public int testPoints { get; set; }
public override int Fitness()
{
return testPoints;
}
}
Then the following would be a compilation error
Human human = new Human() {testPoints = 10};
Fish fish = new Fish() { swimSpeed = 20 };
fish.MoreFitThan(human);
because Human is not a Fish. However this would allow a class that inherits from Fish to be compared to a Fish.
class Trout : Fish
{
public int size { get; set; }
public override int Fitness()
{
return size;
}
}
The following works because a Trout is a Fish.
Trout trout = new Trout() {size = 10};
Fish fish = new Fish() { swimSpeed = 20 };
fish.MoreFitThan(trout);
My suggestion would be to create classes of comparable types, say: Swimmer, Runner, Learner that implement your interface, then in those classes also implement IComparable and enforce the constraint on that class type. Then you can extend those classes with Human for Learner, Fish for Swimmer, etc...
There are other ways to do it, but this should work fine for your needs.

Invalid cast with generic type

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.

Sorting a `List<object>` by object properties

I have some different objects that all of them have a integer field called Place. Is there a way to sort out this list without knowing what is the actual object? I mean just accessing the Place field and sort the list based on this number. possibly using linq or something?
some example objects:
public class Car
{
public int Place;
//Other related fields
}
public class Human
{
public int Place;
//Other related fields
}
//Somwhere in program
List<object> GameObjects;
You should derive your classes from a base class.
public class Base
{
public int Place;
}
public class Car : Base
{
// other properties
}
public class Human : Base
{
// other properties
}
Then you can create a list of your base type, add humans
and cars. After that you can use the Linq Sort or OrderBy method.
List<Base> list = new List<Base>();
list.Add(new Human { Place = 2 });
list.Add(new Car { Place = 1 });
var sortedList = list.Sort(x => x.Place);
More Information
The C# Station Tutorial - Lesson 8: Class Inheritance
MSDN - Queryable.OrderBy
MSDN - List.Sort Method
No because object doesn't have a Place property only Car/Human do.
There are a couple of ways you can solve this problem:
Introduce a base class
public class GameObject
{
public int Place { get; set; }
}
public class Car : GameObject
{}
public class Human : GameObject
{}
...
List<GameObject> GameObjects
Use a generic interface
public interface IGameObject
{
int Place { get; }
}
public class Car : IGameObject
{
public int Place { get; set; }
}
public class Human : IGameObject
{
public int Place { get; set; }
}
List<IGameObject> GameObjects
What you just discovered is relationship between those types. Both Car and Human seem to have a Place property, so you should extract an interface à la IGameObject.
The best way is to use an interface. If you can't, you still can do late binding using the dynamic keyword:
var list = new List<object>
{
new Car { Place = 3 },
new Human { Place = 1 },
new Car { Place = 2 }
};
var sortedList = list.OrderBy(o => ((dynamic)o).Place);
Yes, its possible using delegate methods with reflection. This is upto my knowledge, may be some other giants create it without using reflection
The best you can do is use an Interface, like this:
public Interface IFoo
{
int place;
}
And the implement that interface:
public class Car : IFoo
{
public int Place;
}
public class Human : IFoo
{
public int Place;
}
And then with linq:
List<IFoo> GameObjects;
GameObjects.OrderBy(g => g.Place);
You could let them implement an interface IPlaceable and use a property instead of only a field:
public interface IPlaceable
{
int Place { get; set; }
}
public class Car : IPlaceable
{
public int Place { get; set; }
//Other related fields
}
public class Human : IPlaceable
{
public int Place { get; set; }
//Other related fields
}
// Somwhere in program
List<IPlaceable> GameObjects;
// Somwhere else
GameObjects.OrderBy(go => go.Place);
Note that the list now is a List<IPlaceable> instead of a List<Object>.

Categories