My code structure is something like this
class Drawing()
{
ObjectType = "Drawing";
}
class Shape() : Drawing()
{
DrawingType = "Shape";
}
class square() : Shape()
{
ShapeType = "square";
}
class circle() : Shape()
{
ShapeType = "circle";
}
class triangle() : Shape()
{
ShapeType = "triangle";
}
class lines() : Drawing()
{
DrawingType = "lines";
}
class horizontal() : lines()
{
linesType = "horizontal";
}
class vertical() : lines()
{
linesType = "vertical";
}
etc...
I am trying to figure out the right logic in how to solve this problem so the picture is a simple representation of what I have.
I have a object structure of something like in the picture where they're all inheriting the level above them. They all have properties of its type. They would all have ObjectType, and the 2nd level has DrawingType, and the 3rd level has either ShapeType, LineType, or PointType...
So for example, square would have
square {
ObjectType = "drawing";
DrawingType = "shapes";
ShapeType = "square"
}
However, vertical would have different properties
vertical {
ObjectType = "drawing";
DrawingType = "lines";
LineType = "vertical"
}
Now my problem is, lets say I wanted a user to select something based on their input, how would i do it?
Like lets say the user typed "square", how would I select square? It would be easy if the properties were the same cause I could just compare them. But how would I do it with a structure like this?
As these all classes are derived from one base class hence all the child classes contains the property coming from parents. Object level comparison will lead you comparison of one Drawing object to another as all the objects are derived from there only. Hence i have implemented IComparer to get your desired result ->
Here is the code ->>
Main Class :
Drawing drawing1 = new Drawing();
Drawing drawing2 = new Drawing();
drawing2.ObjectType = "newdrawing";
Shape shape = new Shape();
triangle triangle1 = new triangle();
triangle triangle2 = new triangle();
triangle2.ShapeType = "another";
//all -1 is not equals and 0 is equals
int result1 = drawing1.Compare(drawing1, drawing2);
int result2 = drawing1.Compare(drawing1, drawing1);
int result3 = drawing1.Compare(drawing1, shape);
int result4 = shape.Compare(shape, triangle1);
int result5 = triangle1.Compare(triangle1, triangle2);
Other classes :
public class Drawing : IComparer
{
public string ObjectType { get; set; } = "Drawing";
public int Compare(object x, object y)
{
//returning 0 is equals
if (x.GetType().Name == y.GetType().Name)
{
switch (x.GetType().Name)
{
case "Drawing":
return ((Drawing)x).ObjectType == ((Drawing)y).ObjectType ? 0 : -1;
case "Shape":
return ((Shape)x).DrawingType == ((Shape)y).DrawingType ? 0 : -1;
case "square":
return ((square)x).ShapeType == ((square)y).ShapeType ? 0 : -1;
case "triangle":
return ((triangle)x).ShapeType == ((triangle)y).ShapeType ? 0 : -1;
default:
return -1; // Not equal
}
}
return -1; // Not equal
}
}
class Shape : Drawing
{
public string DrawingType { get; set; } = "Shape";
}
class square : Shape
{
public string ShapeType { get; set; } = "square";
}
class circle : Shape
{
public string ShapeType { get; set; } = "circle";
}
class triangle : Shape
{
public string ShapeType { get; set; } = "triangle";
}
class lines : Drawing
{
public string DrawingType { get; set; } = "lines";
}
class horizontal : lines
{
public string linesType { get; set; } = "horizontal";
}
class vertical : lines
{
public string linesType { get; set; } = "vertical";
}
Hope this will work for you. please write back with you code snippet specifically not working. Cheers
Related
How I can write make method Compare in RoomComparerByVolume ?
"Define a generic class RoomComparerByVolume<> implementing IComparer interface.
Impose a constraint on the type argument so that it should implement the IShape interface.
This comparer should perform comparison of rooms by room volume."
public interface IShape
{
public double Area()
{
return 0;
}
}
public class Rectangle : IShape
{
public double Length { get; set; }
public double Width { get; set; }
public double Area()
{
return Length * Width;
}
}
public class Trapezoid : IShape
{
public double Length1 { get; set; }
public double Length2 { get; set; }
public double Width { get; set; }
public double Area()
{
return (Length1 + Length2) * Width / 2;
}
}
public class Room<T> where T : IShape, ICloneable, IComparable
{
public double Height { get; set; }
public T Floor;
public double Volume()
{
return Height * Height;
}
public object Clone()
{
return new Room<T> { Height = this.Height, Floor = this.Floor };
}
public int CompareTo(object o)
{
Room<T> r = o as Room<T>;
if (r != null)
return this.Volume().CompareTo(r.Volume());
else
throw new Exception("Unable to compare");
}
}
public class RoomComparerByVolume<T> : IComparer<T> where T : IShape
{
}
Your question is a bit unclear. If compare "by room volume" means in fact compare Area() values
and you want to imeplement a corresponding comparer, you can put something like this
public sealed class ShapeComparerByArea<T> : IComparer<T> where T : IShape
{
public int Compare(T left, T right)
{
if (ReferenceEquals(left, right))
return 0;
if (left == null)
return 1;
if (right == null)
return -1;
return left.Area().CompareTo(right.Area());
}
}
If you want to define comparable Room class (which has Shape Floor) you can put it as
public class Room : IComparable<Room> {
public Room(IShape floor, double height) {
Floor = floor ?? throw new ArgumentNullException(nameof(floor));
Height = height > 0
? height
: throw new ArgumentOutOfRangeException(nameof(height));
}
public IShape Floor { get; }
public double Height { get; }
public double Volume => Floor.Area() * Height;
public int CompareTo(Room other) {
if (ReferenceEquals(this, other))
return 0;
if (other is null)
return 1;
return Volume.CompareTo(other.Volume);
}
}
Finally, RoomComparerByVolume can be
public sealed class RoomComparerByVolume : IComparer<Room> {
public int Compare(Room left, Room right) {
if (ReferenceEquals(left, right))
return 0;
if (left == null)
return 1;
if (right == null)
return -1;
return left.Volume.CompareTo(right.Volume);
}
}
Demo:
Room myRoom = new Room(
new Trapezoid() { Length1 = 5, Length2 = 7, Width = 3},
2.8);
Room myOtherRoom = new Room(
new Rectangle() { Length = 3, Width = 4 },
2.5);
Console.WriteLine(myRoom.CompareTo(myOtherRoom));
RoomComparerByVolume comparer = new RoomComparerByVolume();
Console.WriteLine(comparer.Compare(myRoom, myOtherRoom));
I would assume that the desired declaration should look like
public class RoomComparerByVolume<T> : IComparer<Room<T>> where T : IShape, ICloneable, IComparable{
public int Compare(Room<T> left, Room<T> right) {
...
}
That way you can compare the two rooms. But note that the two rooms need to be the same shape using this method. Also note that you need to use the same generic constraints as you are using for Room<T>.
Also note that in many cases you do not need to create a specific comparer type. Often you can use a delegate to do the actual comparison:
Comparer<Room<Trapezoid>>.Create((l, r) => l.Volume().CompareTo(r.Volume));
I have a generic method
class Program {
Character CreateChar<T>() where T : new() {
T DChar = new T();
Character Char = new Character {
Name = DChar.Name,
Health = DChar.Health
};
return Char;
}
public static void Main() {
Character Char1 = CreateChar<Mage>();
}
}
Where I have a Character class, and that has the basic stuff like Name, Health, ect.
class Character {
public string Name { get; set; }
public int Health { get; set; }
}
But (this is like a game) I have some set types like "Mage".
class Mage {
public int Health {
get {
return 5;
}
}
}
So my idea was to make a generic method "CreateChar" so I can pass Mage to it like so in Main:
Character Char1 = CreateChar<Mage>();
However I can't seem to access DChar.Name or DChar.Health since "T does not contain a definition for 'Health'". So, is there a way to access the T method? Or is there just a better way of handling this?
In fact, now that I see it, "CreateChar();" is invalid as well because "an object reference is required for a nonstatic field". So I guess my question is, what is wrong, and how do I fix it?
In a generic method, you can only access the methods defined by the constraint on T (unless you use reflection or type checking/casting, both of which defeat the purpose of generics). If you constrain T to a Character (which I think you have to do to access Name and Health), then it should work (please post the Character class with relevant properties). But then in order to pass it a Mage, you'd have to have Mage inherit from Character.
Here's what I mean; first create an interface that defines properties that all characters will have (i.e. all public properties, methods, and events):
public interface ICharacter
{
string Name { get; set; }
string Description { get; }
int Health { get; set; }
}
Then we can create a base class called Character that implements the interface::
public class Character : ICharacter
{
public string Name { get; set; } = "Default Character";
public int Health { get; set; } = 5;
public string Description { get; protected set; } = "Default Description";
}
Next we create some character types that inherit the Character class:
public class Mage : Character
{
public Mage()
{
Name = "Default Mage";
Description = "Someone who uses or practices magic " +
"derived from supernatural or occult sources.";
}
}
public class Elf : Character
{
public Elf()
{
Name = "Default Elf";
Description = "A supernatural creature of folk tales, " +
"typically represented as a small, elusive figure " +
"in human form with pointed ears, magical powers, " +
"and a capricious nature.";
}
}
So now we can constrian our generic type T to the ICharacter interface, and we can access the Name and Health properties:
class Program
{
T CreateChar<T>() where T : ICharacter, new()
{
var result = new T();
result.Name += " (created in 'CreateChar' method)"; // Modify a property
return result;
}
// Rest of class omitted
}
You need to constrain T to an interface or a base class that contains the method you want to call.
I think you are looking at a factory pattern here. Does this help?
public class Character
{
protected Character(string name, int health)
{
Name=name;
Health=health;
}
public string Name { get; set; }
public int Health { get; set; }
}
public class Mage : Character
{
public Mage() : base("Evil Mage", 5)
{
this.Mana = 10;
}
public int Mana { get; set; }
}
public class Paladin : Character
{
public Paladin() : base("Holy Paladin", 8)
{
this.Shield = 2;
}
public int Shield { get; set; }
}
public static class ChatacterFactory
{
public static TChar Create<TChar>(string name) where TChar : Character, new()
{
var result = new TChar();
result.Name = name;
return result;
}
}
class Program
{
static void Main(string[] args)
{
Mage mage = ChatacterFactory.Create<Mage>("Boom Mage");
Paladin paladin = ChatacterFactory.Create<Paladin>("White Knight");
}
}
if I understood you right one of these should work for you:
//case 1
class Character1
{
static Character1 CreateChar<T>(T character) where T : CommonGameCharecterClassOrInterface, new()
{
Character1 achar = new Character1
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
class Character2
{
static Character2 CreateChar(dynamic character)
{
Character2 achar = new Character2
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
//case 2
class Character3
{
static Character3 CreateChar<T>() where T : CommonGameCharecterClassOrInterface, new()
{
T character = new T();
Character3 achar = new Character3
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
class Character4
{
static Character4 CreateChar<T>() where T : new()
{
dynamic character = new T();
Character4 achar = new Character4
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
I have a list of source classes derived from a base source class and a list with destination classes derived from a base destination class. There is only one destination class corresponding to a source class. I want to make a generic converter which updates an existing destination object, given his corresponding source object.
Updated completely:
I have the following code:
using System;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
S1 newItem = new S1()
{
Age = 11,
Name = "John"
};
D1 oldItem = new D1()
{
Age = 10
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<S1, D1> convertor = new Convertor<S1, D1>(newItem, oldItem);
S2 newItem2 = new S2()
{
City = "London",
Name = "Lynda"
};
D2 oldItem2 = new D2()
{
City = "Paris"
};
Convertor<S2, D2> convertor2 = new Convertor<S2, D2>(newItem2, oldItem2);
Console.ReadKey();
}
}
public abstract class SourceDomain
{
public string Name { get; set; }
internal abstract void SetItem<Y>(Y oldItem) where Y : DestinationDomain;
}
public class S1 : SourceDomain
{
public int Age { get; set; }
internal override void SetItem<Y>(Y oldItem)
{
Console.WriteLine("here I want to update the age of oldItem (10) with the new value (11)");
//oldItem.Age = Age;
}
}
public class S2 : SourceDomain
{
public string City { get; set; }
internal override void SetItem<Y>(Y oldItem)
{
Console.WriteLine("here I want to update the city of oldItem Paris with the new value London");
// oldItem.City = City;
}
}
public class DestinationDomain { }
public class D1 : DestinationDomain
{
public int Age { get; set; }
}
public class D2 : DestinationDomain
{
public string City { get; set; }
}
public class Convertor<X, Y> where X : SourceDomain where Y : DestinationDomain
{
protected X item;
protected Y oldItem;
public Convertor(X newObject, Y oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of item type, the proper method, not the base one.
item.SetItem(oldItem);
}
}
}
SourceDomain and DestinationDomain are base classes and there are a lot of derived classes for each of them S1, S2, D1, D2, etc.
This converter receives two classes as types and two objects of that classes and tries to update the destination item of type Y with source item of type X.
In the above example, I want to change update the age of the D1 oldItem variable with 11, and the City oldItem2 with the "London" value, but I cannot access that properties in SetItem method.
This needs to be done with a combination of inheritance and generics, and we'll make the two work together with generic type constraints.
Here are the requirements as I understand them:
You've got some data you want to copy from Source to Destination; one kind of data has an Age, one has a City, maybe another has a Poodle or a SwimmingPool. We'll define an interface that says: "This is a data object which can copy its own properties from another object of the same type", and we'll put all our data in little classes which know how to copy themselves. The "I can copy things like me" interface doesn't know what properties will be copied; it just requires the concrete class to implement a method that knows those details internally. As far as this example goes it could be a base class, but my assumption is the “copyability” isn’t the core indentity of these objects. It’s not what they represent; it’s just one thing we need to be able to do with them along the way.
The other things we need are a "source thing", and a "destination thing". A source thing just needs to provide a data object that can be copied. A destination thing just needs to receive a data object that can be copied.
You confused yourself by trying to mix up the sources and destinations with the data items. If you're going crazy trying to make your class do two contradictory things at once, try breaking it up into two classes that each does one thing.
You never do anything with your SourceDomain Name property, so I won't either. If you need to, I'll leave that as an exercise.
public interface ICopyable<T>
{
void CopyFrom(T other);
}
internal class Program
{
private static void Main(string[] args)
{
var newItem = new SourceDomain<Person>
{
Item = new Person { Age = 11 },
Name = "John"
};
var oldItem = new DestinationDomain<Person>
{
Item = new Person { Age = 10 }
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<Person> convertor = new Convertor<Person>(newItem, oldItem);
var newItem2 = new SourceDomain<Location>()
{
Item = new Location { City = "London" },
Name = "Lynda"
};
var oldItem2 = new DestinationDomain<Location>()
{
Item = new Location { City = "Paris" }
};
Convertor<Location> convertor2 = new Convertor<Location>(newItem2, oldItem2);
Console.ReadKey();
}
}
public class SourceDomain<T>
{
public string Name { get; set; }
public T Item { get; set; }
}
public class DestinationDomain<T> where T : ICopyable<T>, new()
{
public string Name { get; set; }
public T Item { get; set; }
public void CopyItemFrom(T other)
{
if (Item == null)
{
Item = new T();
}
Item.CopyFrom(other);
}
}
// A person is a thing which can turn itself into a copy of another Person.
// You could define a class Wombat : ICopyable<Locomotive>, if you wanted to be
// able to convert Locomotives to Wombats. You'd just add another CopyFrom()
// overload, public void CopyFrom(Locomotive other).
public class Person : ICopyable<Person>
{
public int Age { get; set; }
public void CopyFrom(Person other)
{
Age = other.Age;
}
}
public class Location : ICopyable<Location>
{
public String City { get; set; }
public void CopyFrom(Location other)
{
City = other.City;
}
}
public class Convertor<X> where X : ICopyable<X>, new()
{
protected SourceDomain<X> item;
protected DestinationDomain<X> oldItem;
public Convertor(SourceDomain<X> newObject, DestinationDomain<X> oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of item type, the proper method, not the base one.
//newObject.Data = oldItem.Data;
oldItem.CopyItemFrom(item.Item);
}
}
Homework:
Modify this code so DestinationDomain.CopyItemFrom() receives the source itself, not the source's item.
I think it's better the way I wrote it. Think of reasons why I might have thought that.
Seriously, find out what ref does, and never again use a keyword in your code if you are only guessing about what it might mean. Don't just throw code at the wall, hoping it sticks. You'll get yourself in a lot of frustrating trouble that way.
Finally i have done this:
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
S1 newItem = new S1()
{
Age = 11,
Name = "John"
};
D1 oldItem = new D1()
{
Age = 10
};
//there is an item in a database which is of D1 type. This convertor receives an object S1 in order to update the D1 item.
// the rule is that Sx updatates Dx (where x is 1,2,3,4,5...)
Convertor<S1, D1> convertor = new Convertor<S1, D1>(newItem, oldItem);
S2 newItem2 = new S2()
{
City = "London",
Name = "Lynda"
};
D2 oldItem2 = new D2()
{
City = "Paris"
};
Convertor<S2, D2> convertor2 = new Convertor<S2, D2>(newItem2, oldItem2);
Console.ReadKey();
}
}
public interface ICopyable<T>
{
void CopyFrom(T other);
}
public abstract class SourceDomain
{
public string Name { get; set; }
}
public class S1 : SourceDomain
{
public int Age { get; set; }
}
public class S2 : SourceDomain
{
public string City { get; set; }
}
public class DestinationDomain { }
public class D1 : DestinationDomain, ICopyable<S1>
{
public int Age { get; set; }
public void CopyFrom(S1 other)
{
Console.WriteLine("oldItem.Age " + Age + " new Age; = " + other.Age);
Age = other.Age;
Console.WriteLine("oldItem.Age " + Age + " new Age; = " + other.Age);
}
}
public class D2 : DestinationDomain, ICopyable<S2>
{
public string City { get; set; }
public void CopyFrom(S2 other)
{
City = other.City;
Console.WriteLine(" oldItem.City = City;");
}
}
public class Convertor<X, Y> where X : SourceDomain where Y : DestinationDomain, ICopyable<X>
{
protected X item;
protected Y oldItem;
public Convertor(X newObject, Y oldObject)
{
item = newObject;
oldItem = oldObject;
//here I want to call, depending of X type, the proper method, not the base one.
oldItem.CopyFrom(item);
Console.WriteLine(item);
}
}
}
I'm playing with C# generics and interfaces today and trying implement classic definition of Graphs. Here is my best attempt (for exercise only):
interface IVertex
{
string Name { get; set; }
}
interface IEdge<V> where V : IVertex
{
V From { get; set; }
V To { get; set; }
}
interface IGraph<V, E> where E: IEdge<V> where V: IVertex
{
IList<V> Vertices { get; }
IList<E> Edges { get; }
}
class Vertex : IVertex
{
public string Name { get; set; }
public Vertex(string name)
{
Name = name;
}
}
class Edge<V> : IEdge<V> where V: IVertex
{
public V From { get; set; }
public V To { get; set; }
public Edge(V from, V to)
{
From = from;
To = to;
}
}
class Graph<V, E> : IGraph<V, E> where E: IEdge<V> where V : IVertex
{
public IList<V> Vertices { get; } = new List<V>();
public IList<E> Edges { get; } = new List<E>();
}
But I think, that I'm doing something wrong, because in following usage:
var a = new Vertex("A");
var b = new Vertex("B");
var c = new Vertex("C");
var x = new Edge<Vertex>(a, b);
var y = new Edge<Vertex>(b, c);
var z = new Edge<Vertex>(c, a);
var graph = new Graph<Vertex, Edge<Vertex>>()
{
Vertices = { a, b, c },
Edges = {x, y, z}
};
I need to specify the generic argument Vertex (at line new Graph<Vertex, Edge<Vertex>>()) twice...
Without more context, it's not clear what your constraints and requirements are. But, depending on what you're trying to accomplish, the syntax you currently have may be required, to ensure that your IList<E> is declared appropriately.
It is also possible that you don't require the Graph class to have the exact IEdge<V> type. If so, then you could declare it like this:
class Graph<V> : IGraph<V, IEdge<V>> where V : IVertex
{
public IList<V> Vertices { get; } = new List<V>();
public IList<IEdge<V>> Edges { get; } = new List<IEdge<V>>();
}
In this approach, you will not be able e.g. to assign Edges to a variable of type IList<E> where E is some type other than IEdge<V>. For example, this wouldn't work, while it would work if you require both types to be specified:
IList<Edge<Vertex>> list = graph.Edges;
It all depends on how you actually want to use these types.
I define two interfaces as following:
public interface IData
{
double value { set; get; }
}
public interface IInterval<C, M>
{
C left { set; get; }
M data { set; get; }
}
Then I use these two interfaces for following class declaration.
public class TESTClass<I, M>
where I : IInterval<int, M>, new()
where M : IData
{
public I interval{ set; get; }
public TESTClass()
{
// This is invalid, cos property value is not visible at initialization ...
interval = new I() { left = 0, data.value = 0 };
// instead I have to do as:
interval = new I() { left = 0 };
interval.data.value = 0;
}
}
am I missing something here ?
I would appreciate if you could help me figure this out.
Well, you could certainly do that. Syntax is bit different.
public TESTClass()
{
interval = new I()
{
left = 0,
data = //Reads data property,
{
value = 0 //set data.value to 0
}
}
}
You can't access sub-properties in object initializers using the member-access operator (.).
This works:
public class TESTClass<I, M>
where I : IInterval<int, M>, new()
where M : IData, new()
{
public I interval{ set; get; }
public TESTClass()
{
interval = new I() { left = 0, data = new M {value = 0} };
}
}