i am studying C# online , and i faced this thing a couldn't understand it ,
consider this Animal class
public class Animal
{
public int Age { set; get; }
public string Name { set; get; }
public double Weight { set; get; }
public Animal()
{ }
public Animal(int Age, string Name, double Weight)
{
this.Age = Age;
this.Name = Name;
this.Weight = Weight;
}
}
And the Dog class which inherit from Animal
class Dog : Animal
{
public string color { set; get; }
public Dog()
{
}
public Dog(int Age, string Name, double Weight, string color) : base(Age, Name, Weight)
{
this.color = color;
}
public string EmptyMethod()
{
return(" i am dog method ");
}
}
In the Main method in program class
static void Main(string[] args)
{
List<Animal> MyAnimals = new List<Animal>();
List<Dog> MyDogs = new List<Dog>();
MyAnimals.Add(new Animal());
MyAnimals.Add(new Dog());
foreach (var item in MyAnimals)
{
Console.WriteLine(item.GetType().Name);
if (item is Dog)
{
Console.WriteLine(item.GetType().Name + " i am dog between Animal");
//Here i got a compiling error and can't reach the dog empty method even after checking it's a Dog object !!! Why
var tryingToReachDogMethod = item.EmptyMethod();
}
}
Animal smallAnimal = new Animal();
MyDogs.Add(new Dog());
MyDogs.Add(smallAnimal as Dog);
foreach (var item in MyDogs)
{
//Here i Can reach the Empty Method from Dog Class !!!
//i know it will give runtime error because some objects is not
//dogs and don't have it's method to implement it
var tryingToReachDogMethod = item.EmptyMethod();
if (item is Animal)
{
Console.WriteLine("i am animal as dog");
}
}
I comment My question in the third piece of code ,(the code is one of my exercises i have written few days ago) , so why would a programmer make a list of animals then put a more developed object in it (in the example object from class dog) and why any one would to do the opposite ? why to make a list from developed object (in the example dogs) and then try to put Less developed type of objects in it ,
Can you give example from real programming solution
MyDogs is a list of dogs. You can add only Dogs to it.
The problem is in this line:
MyDogs.Add(smallAnimal as Dog);
You probably think you casted the animal to a dog. That is not true. You tried to cast it, but it failed. Since you use as, it will not throw an exception, but instead will return null. Now you have a null Dog in your list. You will get a null reference exception when you try to access members of that instance.
Cause item is still Animal since you have List<Animal> MyAnimals = new List<Animal>(); and your Animal type don't have a EmptyMethod(). Thus you need to cast it to Dog type explicitly like below in order to invoke the desired method
var tryingToReachDogMethod = ((Dog)item).EmptyMethod()
(Or) You can as well use as operator along with null propagation operator like
Dog d = item as Dog;
var tryingToReachDogMethod = d?.EmptyMethod();
Real world example of where it makes sense to put a (as you call it) "more developed" version of an object inside a list defined using a base class or interface is the "Command" pattern.
Given an interface like this:
public interface ICommand
{
void Execute();
}
You might have lots of different implementations of ICommand that you want to execute one after another. You would put them all in some sort of List
var commands = new List<ICommand>();
commands.Add(new Command1());
commands.Add(new Command2());
And execute them all. You dont need to know what sort of command it is, just that they all have an Execute method
foreach(var command in commands)
command.Execute();
This demonstrates Polymorphism
Related
I have these classes
class Start
{
public List<Base> list { get; set; }
public Start()
{
list = new List<Base>();
}
}
public abstract class Base
{
public int a { get; set; }
}
class B : Base
{
public int b;
public B(int a, int b) { this.a = a; this.b = b; }
}
class C : Base
{
public int c;
public C(int a, int c) { this.a = a; this.c = c; }
}
I want list property of class Start to hold instances of class B or instances of class C (not both together, but it may hold the same type of any of B or C)
If possible, I don't want to use Generics
In C#, This is possible:
List<Object> lst = new List<Object>();
lst.Add(1);
list.Add("Text");
Console.WriteLine("{0} {1}", lst[0], lst[1]);
I don't understand why I can't make a similar behavior here:
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
Console.WriteLine(s.list[0].a); //works
Console.WriteLine(s.list[0].b); //doesn't work
The difference between the two snippets is that in the first one you are not accessing any type-specific information (fields/properties/methods), i.e. something like the following will not compile too:
List<Object> lst = new List<Object>();
lst.Add(1);
list.Add("Text");
// will not compile despite string having Length property:
Console.WriteLine("{0} {1}", lst[0], lst[1].Length);
a is common property declared in Base class, so it is available for every child of Base, if you want to access child specific properties you need to type test/cast :
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
Console.WriteLine(s.list[0].a); //works
if(s.list[0] is B b)
{
Console.WriteLine(b.b);
}
or make Start generic:
class Start<T> where T: Base
{
public List<T> list { get; set; }
public Start()
{
list = new List<T>();
}
}
var s = new Start<B>();
s.list.Add(new B(1, 2));
Console.WriteLine(s.list[0].b);
P.S.
Note that overriding ToString in Base, B and A will make Console.WriteLine("{0}", s.list[0]); "work":
class B : Base
{
// ...
public override string ToString() => return $"B(A: {a} B: {b})";
}
class C : Base
{
// ...
public override string ToString() => return $"C(A: {a} B: {c})";
}
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
s.list.Add(new C(4, 2));
Console.WriteLine("{0} {1}", s.list[0], s.list[1]); // prints "B(A: 1 B: 2) C(A: 4 B: 2)"
So possibly you can introduce some method in Base which will allow you to use List<Base> (hard to tell without knowing actual use case).
The List<Object> example is possible because both int and string inherit from Object, which provides a ToString() method that is called implicitly on the line that writes the output. That is, no members of either the int or string types are used in that example that are specific to their own types.
You might accomplish what you need without generics by adding an interface that both B and C can implement, since both the b and c properties are compatible (they are both ints). However, this is clearly a contrived example, and I expect the real code is more complicated. In that case, generics are likely your best option.
because all Base objects dont have 'b' fields
you need to test to see if list[0] is an instance of 'B' and then cast it to a B
if (list[0] is B )
{
Console.WriteLine(((B)(list[0]).b);
}
Based on the comments underneath the question, perhaps a combination of both a non-generic interface and a generic Start class could work in this scenario.
The non-generic base interface for the generic Start class would declare a get-only List property as IReadOnlyList<Base>. IReadOnlyList is co-variant, allowing to return different List<T> instances where T is a concrete derived type from Base.
public interface IStart
{
IReadOnlyList<Base> List { get; }
}
The generic Start<TBase> class implements IStart, puts the IStart.List property in an explicit interface declaration and declares its own List property that is typed as List<TBase>.
public class Start<TBase> : IStart where TBase : Base
{
public List<TBase> List { get; set; }
IReadOnlyList<Base> IStart.List => this.List;
public Start()
{
List = new List<TBase>();
}
}
Note that both the explicit interface implementation of IStart.List and Start<TBase>'s own List property return the same List<TBase> instance.
This setup makes the following things possible (or impossible, see the code comments):
var startC = new Start<C>();
startC.List.Add(new C()); // this works, of course it works
startC.List.Add(new B()); // The compiler will NOT allow this
IStart SomeMethodProducingAStart()
{
if (someCondition)
return new Start<B>();
else
return new Start<C>();
}
void SomeMethodConsumingAStart(IStart start)
{
if (start is Start<B> startWithBs)
{
// do stuff with startWithBs...
Console.WriteLine(startWithBs.List[0].a);
Console.WriteLine(startWithBs.List[0].b);
}
else if (start is Start<C> startWithCs)
{
// do stuff with startWithCs...
Console.WriteLine(startWithCs.List[0].a);
Console.WriteLine(startWithCs.List[0].c);
}
// if you don't care about the members specific to either B or C,
// just do this
Console.WriteLine(start.List[0].a);
// since start can be any Start<T>
// the following is denied by the compiler
// simply by virtue of IStart.List being an IReadOnlyList
start.List.Add(new C()); // no can do!
}
Whether this approach fits your application scenario well is for you to determine, but it's an approach that tries to avoid granular pattern matching on individual list items and aims at simplifying working with Start instances once they have been pattern-matched/cast to the correct Start<TBase> type.
I'm new to C# and am currently trying to figure out the best way to implement the following:
I have a list of species with an associated group:
Bird: "Budgie", "Parrot"
Dog: "Pitbull", "Labrador"
Cat: "Cheetah", "Lion"
Given a string of an animal, I need to return its group.
eg. "Cheetah" would return "Cat".
I have implemented the following:
// create list one and store values
List<string> valSetOne = new List<string>();
valSetOne.Add("Budgie");
valSetOne.Add("Parrot");
// create list two and store values
List<String> valSetTwo = new List<String>();
valSetTwo.Add("Lion");
valSetTwo.Add("Cheetah");
// create list three and store values
List<String> valSetThree = new List<String>();
valSetThree.Add("Labrador");
valSetThree.Add("Pitbull");
// add values into map
map.Add("Bird", valSetOne);
map.Add("Cat", valSetTwo);
map.Add("Dog", valSetThree);
foreach(KeyValuePair<string, List<string>> kvp in map){
foreach(string value in kvp.Value)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, value);
}
}
Instead of having a foreach loop, is there a faster way to find the key given an animal value?
//EDIT:
Currently trying to initialize with a Tuple
var tupleList = new List<Tuple<string, List<string>>>
{
new Tuple<string, List<string>>("cat", { "cheetah", "lion"})
};
I'm getting the following error: Unexpected symbol `{'
A better modeling of the data will be to create a class of the group which will have a name and a collection of animals in it. Then you can hold a collection of groups and query it.
If you want to stick with the dictionary then: As your question is to retrieve the key for a given value out of the list of values for that key, I'd organize the data the other way around:
var map = new Dictionary<string,string>
{
["Cheetah"] = "Cat",
["Lion"] = "Cat",
//....
};
Then you can search by your real key - which is the species and not the group:
if(map.TryGetValue("Lion", out var group)) { }
As it is easier to construct the data by grouping to list of species you can:
var rawData = new List<(string group, List<string> species)>
{
("Cat", new List<string> { "Cheetah", "Lion" }),
//...
};
var result = rawData.SelectMany(item => item.species.Select(s => (s, item.group)))
.ToDictionary(k => k.s, v => v.group);
This works with C#7.0 named tuples. If you are using a previous version you can use anonymous types or "old fashion" tuples
For a pre C# 7.0 initialization of the collection:
var rawData = new List<Tuple<string, List<string>>>
{
Tuple.Create<string,List<string>> ("Cat", new List<string> { "Cheetah", "Lion" })
};
If you don't want to use another way to store your data and you store them in a dictionary with keys the animal species, I would suggest you change the type of the value that is associated with each key, to a HashSet
Dictionary<string, HashSet<string>>
Doing so you can iterate through the keys (O(n), where n is the number of keys) of the dictionary and using HashSet Contains method in O(1) you can find out if the animal is associated with the current key/spiece or not.
Using your existing dictionary structure, you can do this:
string cheetahGroup = map.FirstOrDefault(item =>
item.Value.Contains("cheetah", StringComparer.OrdinalIgnoreCase)).Key;
Note that if the animal doesn't exist, then cheetahGroup will be null. In the case above, it will be "Cat".
As others have suggested I think you should use classes here. But other responses stop at 1 level of classes. I would recommend a more holistic object-oriented approach.
public abstract class Animal {}
public abstract class Dog : Animal {}
public abstract class Cat : Animal {}
public abstract class Bird : Animal {}
public sealed class Budgie : Bird {}
public sealed class Parrot : Bird {}
public sealed class Pitbull : Dog {}
public sealed class Labrador : Dog {}
public sealed class Cheetah : Cat {}
public sealed class Lion : Cat {}
[note that sealed is optional here]
then you just say
Labrador spot = new Labrador();
to check if it's a dog
if (spot is Dog) {
print("it's a dog");
}
This solution has the option of being easily extensible, and super easy to read. There's not weird code that distracts you from the fact that a Labrador is a dog, and a budgie is a bird. It's very clear what you're trying to do and what classes Dog, Cat, Cheetah, etc represent.
If you further wanted to split up labradors into Chocolate, Yellow, and Black, you could just add another layer of classes inheriting from Labrador. If you needed to define the properties of the animals, that's easy too. For example if you only wanted Dogs and Cats to have names, you could add a name field in their classes, whereas if you want all animals to have a name you can put the name field in the Animal class.
If you needed to move the animals, you could at the animal level define a method called Move() that forces its children to override this method in their own way, so perhaps dogs would Move() by Walking(), whereas birds would Move() by Flying().
I would seriously recommending abandoning the dictionary and think about using something similar to what I described. If you start to think this way it will really help you plan out more complex projects and tasks. There's a reason Object Oriented Programming is so widespread!
I would make a class Animal, since you are working with animals, that would have two properties: Species and SubSpecies
public class Animal
{
public string Species { get; set; }
public string SubSpecies { get; set; }
public Animal(string Species, string SubSpecies)
{
this.Species = Species;
this.SubSpecies = SubSpecies;
}
}
Then you can instanciate all your animals inside a list :
List<Animal> myAnimals = new List<Animal>();
myAnimals.Add(new Animal("Bird", "Budgie"));
myAnimals.Add(new Animal("Bird", "Parrot"));
myAnimals.Add(new Animal("Dog", "Pitbull"));
myAnimals.Add(new Animal("Dog", "Labrador"));
myAnimals.Add(new Animal("Cat", "Cheetah"));
myAnimals.Add(new Animal("Cat", "Lion"));
And finally, you can use Linq to find whatever you're looking for:
//Will return null if the subSpecies doesn't exist
public string FindTheSpecies(string SubSpecies)
{
return myAnimals.FirstOrDefault(x => x.SubSpecies == SubSpecies)?.Species;
}
I have multiple types of object instances that inherit from a common interface.
I would like to access the common methods from each objects by iterating through a list or arraylist or collections. how do I do that?
{
interface ICommon
{
string getName();
}
class Animal : ICommon
{
public string getName()
{
return myName;
}
}
class Students : ICommon
{
public string getName()
{
return myName;
}
}
class School : ICommon
{
public string getName()
{
return myName;
}
}
}
When I add the animal, student, and School in an object[], and try to access
in a loop like
for (loop)
{
object[n].getName // getName is not possible here.
//This is what I would like to have.
or
a = object[n];
a.getName // this is also not working.
}
is it possible to access the common method of different types in from a list or collections?
You need to either cast the object to ICommon
var a = (ICommon)object[n];
a.getName();
Or perferably you should use an array of ICommon
ICommon[] commonArray = new ICommon[5];
...
commonArray[0] = new Animal();
...
commonArray[0].getName();
Or you might want to consider using a List<ICommon>
List<ICommon> commonList = new List<ICommon>();
...
commonList.Add(new Animal());
...
commonList[0].getName();
Just use an "ICommon" array instead of using an "Object" array, otherwise when you retrieve the items of the "Object" array you will have to cast them.
Consider following method:
public PrintObjectHierarchy(object o)
{
Console.WriteLine(o.GetType.FullName);
object baseObject = PruneObjectToItsBaseObject(o);
if(!baseObject.GetType().Equals(typeof(object)))
PrintObjectHierarchy(baseObject);
else Console.WriteLine("System.Object");
}
For example if I wrote:
class Form1 : Form
{
static void Main()
{
Form1 f1 = new Form1();
PrintObjectHierarchy(f1);
}
}
Then it should print for me:
MyNamespace.Form1
System.Windows.Form
System.Windows.Forms.ContainerControl
/*and so so till...*/
System.Object
But unforunately, even if I CAST object to its BaseType, "C# Polymorphism" just will limit its VIEW to the base type and does not return a REAL reference from a REAL base object to me! Let's describe it by an example; if I have
class Person {
public string Name;
public string LastName;
}
class President : Person {
public string password;
}
main(){
President pr = new President() {Name="John"; LastName="Smith"; password="js123" };
Person p = (Person)pr;
SendToAirportSystemAcrossInternet(p);
}
While we think that p is a Person but it's not! it's the President and p is just a view from it, so the president's password will travel across the Internet!
Any idea about how to prune or slice an object to it's base to creating a real base object?
Thanks in advance!
Daniel's solution works; another similar approach would be to write an "copy constructor" and create a new person that way.
So, your person class becomes:
public class Person
{
public Person()
{
}
public Person(Person p)
{
this.name = p.name;
this.lastName = p.lastName
}
public string name;
public string lastName;
}
And you can create a person from a president like this:
President pres = new President() { name = "abc", lastName = "def", password = "kittens" };
Person p = new Person(pres);
This creates a person from a president but there is no way to get back to the president, and no way to get the password. If you create a person this was and cast to a president you will get an InvalidCastException, which I think is what you want.
It's not quite obvious what you're trying to achieve, but as you're interested in your object's inheritance hierarchy you'll most likely want to deal with instances of System.Type. Here's a working version of the first method you posted which might give you a hint on how to proceed from there:
static void PrintObjectHierarchy(object o)
{
Type t = o.GetType();
while (t != null)
{
Console.WriteLine(t.FullName);
t = t.BaseType;
}
}
Basically, you can't do what you want. You should redesign so that you don't have this requirement.
As I noted in comments, it may be that a set of fields in a base class is valid when the execution-time type is a derived class, but is invalid for an instance of just that class. Additionally, there may be all kinds of other safeguards which simply become invalid when an object is viewed in this way. For example, the base class may hold a reference to a collection of values, with the derived class expected to validate the values added to that collection. When the object is "pruned", that validation would be removed, but with a reference to the same collection as before:
// EvenNumbersOnlyCollection rejects odd numbers
EvenNumberCollection derived = new EvenNumbersOnlyCollection();
NumberCollection pruned = Prune<NumberCollection>(derived);
pruned.Add(5);
// This would return 5 - the invariant is broken!
int shouldBeEven = derived.First();
It's not clear why you think that this pruning would be a good idea, but you should try to achieve your wider goal in some other way.
When an object is created in C# is casted always to its original type. Even if you're using it as a base object or an interface, the call p.GetType() will always return the original type.
If you need to create a new object and then you need want to prune to its base object, you need to create a new object of type. For example:
public class ParentClass
{
public Parent(int feature1)
{
mFeature1 = feature1;
}
}
public class ChildClass : ParentClass
{
public ChildClass(int feature1, int feature2) : base(feature1)
{
mFeature2 = feature2;
}
}
...
...
ChildClass cc = new ChildClass(10, 20);
ParentClass pc = (ParentClass)cc; // pc still is of type ChildClass
ParentClass ccAsParent = new ParentClass(cc.Feature1); //ccAsParent is of type ParentClass
...
...
Remember that you can only do this if the parent class is not abstract.
I am trying to cast a list of objects within a consturctor for a derive class IntersectionPath as follows.
public class IntersectionPath : Path<IntersectionSegment>, IEnumerable
{
//Constructors
public IntersectionPath() : base() { Verts = null; }
public IntersectionPath(List<Intersection> inVerts, List<Segment<Node>> inEdges) : base()
{
this.Segments = (List<IntersectionSegment>) inEdges;
}
}
Segments is defined in the generic base class Path
public class Path<T> : IEnumerable<T> where T : Segment<Node>
{
//public properties
public List<Direction> Directions {get; set; }
public List<T> Segments { get; set; }
}
I have defined an explicit operator for the cast within the IntersectionSegment class (see below and so am unclear as to why this won't compile. I have an error message for the casting within the IntersectionPath constructor.
public class IntersectionSegment : Segment<Intersection>
{
//curves which intersect the primary curve at I0(Start Node) and I1(End Node)
public Curve C0 { get; set; }
public Curve C1 { get; set; }
public IntersectionSegment():base() {}
public IntersectionSegment(Intersection n0, Intersection n1):base(n0,n1){}
public static explicit operator IntersectionSegment(Segment<Node> s)
{
if ((s.Start is Intersection) && (s.End is Intersection))
{
return new IntersectionSegment(s.Start as Intersection,s.End as Intersection);
}
else return null;
}
public static explicit operator List<IntersectionSegment>(List<Segment<Node>> ls)
{
List<IntersectionSegment> lsout = new List<IntersectionSegment>();
foreach (Segment<Node> s in ls)
{
if ((s.Start is Intersection) && (s.End is Intersection))
{
lsout.Add(new IntersectionSegment(s.Start as Intersection,s.End as Intersection));
}
else return null;
}
return lsout;
}
Segment is defined as:
public class Segment <T> : Shape where T : Node
{
//generic properties
public T Start { get; set; }
public T End { get; set; }
}
List<InteractionSegment> is not the same as InteractionSegment. Casting a list of one type to a list of another type won't cast each item.
You need to do something like this:
this.Segments = inEdges.Select(x => (InteractionSegment)x).ToList();
This uses LINQ to Objects to cast each object in inEdges to an InteractionSegment object and puts the result back into a list that is then assigned to this.Segments.
Let's look at a far less confusing example.
class Animal {}
class Giraffe : Animal {}
class Tiger : Animal {}
...
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = (List<Animal>) giraffes; // illegal
Your question is I believe "why is the cast on the last line illegal?"
Let's suppose it was legal. Now we add another line:
animals.Add(new Tiger());
You can add a tiger to a list of animals, right? But that list of animals is actually a list of giraffes. The cast does not copy the list, it says "I want to treat this object as being of this type". But since doing so would allow you to do crazy things like putting a tiger into a list of giraffes, we make the cast illegal.
Your situation is just a much more complicated version of the same situation.
This question gets asked almost every day on StackOverflow. Look for "covariance and contravariance" and you will find dozens of examples.
It doesn't work simply because a List<Segment<Node>> is not a List<IntersectionSegment>. If you want to create the later your can use Cast() to explicitly cast each item in the list to the type you want:
this.Segments = inEdges.Cast<IntersectionSegment>().ToList();