I have a short presentation at school for relations between classes (UML), and I want to show with code how composition and aggregation work in practical use and the difference between them. In order to do that however I want to be able to be able to see all active objects atm, to proove that the object I deleted and the object that was part of it are truly gone now.
This is a quick example of what I am trying to do:
List<Company>companies = new List<Company>(){
new Company(){
Name = "Greiner",
new Boss(){
Name = "Hugo",
},
},
};
Company comp = companies.FirstOrDefault();
companies.Remove(comp);
Now I want to somehow show that the Boss is gone along with the company, not just the (indirect) reference to him. So I thought of looking at all active objects.
Is there any way to do this? I am aware that the garbage collector is supposed to do this, but I dont want to tell my fellow students to just believe my words.
Also I do tend to think overly complicated, so my approach might be completely backwards, so any suggestions how to proove the differences between aggregation and composition are welcome.
Regards
Andreas Postolache
You can keep a static counter within your classes to keep count of the no. of instances created. Increment this counter in the constructor and decrease it in the destructor. The class structure sample is shown below.
public class Company
{
public static int counter = 0;
public Company()
{
counter++;
}
public string Name {get;set;}
public Boss Boss { get; set; }
~Company()
{
counter--;
}
}
public class Boss
{
public static int counter = 0;
public Boss()
{
counter++;
}
public string Name {get;set;}
~Boss()
{
counter--;
}
}
Now you can see the no. of instances by printing this counter wherever required.
You can now instantiate your class Company and check the count of objects.
Company company = new Company(){ Name = "Greiner", Boss = new Boss(){ Name = "Hugo" }} ;
Console.WriteLine("Company: " + Company.counter.ToString());
Console.WriteLine("Boss: " + Boss.counter.ToString());
company = null;
The output should result in Company: 1 and Boss: 1
Now on a Button Click write the following code
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Company: " + Company.counter.ToString());
Console.WriteLine("Boss: " + Boss.counter.ToString());
Note that you will have to call the garbage collection methods to force immediate collection or else you cannot guarantee when the object will be removed by the GC.
The output will now show 0 for both Company and Boss.
Note: Use GC.Collect only in your classroom for demonstration purposes.
Garbage collection complicates things for you here - perhaps it would be more instructional to show this in native C++ instead. However, you can explicitly call GC.Collect() to force the garbage collection. To be able to track the deletion of the object, you can use the destructor:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ExampleDeletion
{
class Program
{
public class Company
{
public string Name { get; set; }
public Boss CEO { get; set; }
~Company()
{
Console.WriteLine("Company destroyed: " + Name);
}
}
public class Boss
{
public string Name { get; set; }
~Boss()
{
Console.WriteLine("Boss destroyed: " + Name);
}
}
static void Main(string[] args)
{
List<Company> companies = new List<Company>();
Add(ref companies);
Remove(ref companies);
GC.Collect();
Console.ReadLine();
}
static private void Add(ref List<Company> companies)
{
companies.Add(
new Company()
{
Name = "Greiner",
CEO = new Boss()
{
Name = "Hugo"
}
});
}
static private void Remove(ref List<Company> companies)
{
Company comp = companies.FirstOrDefault();
companies.Remove(comp);
}
}
}
One interesting thing I have noticed while trying this out is that if you remove the item from the list in the same scope where it was created, it does not get collected by GC. It looks like there is an implicit reference from the current scope which keeps the object alive. That was the reason why I pushed the creation of the item to a separate function.
Related
I have two classes (Room, Exit) that I think should depend on each other but that causes circular dependency which is a bad thing from what I read.
//problem
public class Game
{
public List<Room> Rooms {get; set;}
}
public class Room
{
public Exit Exit {get; set;}
}
public class Exit
{
public Room NextRoom {get; set;}
}
//Here is my solution
public class Game
{
public List<Room> Rooms {get; set;}
public Room GetNextRoom(Exit exit)
{
//Loops through the rooms list and compares Room.Id by Exit.NextRoomId and returns it
}
}
public class Room
{
public Exit Exit {get; set;}
}
public class Exit
{
public string NextRoomId {get;set;}
}
My question is if my solution is somewhat right or if there is another better solution to this problem. This breaks the circular dependency but makes it ugly when declaring the Exit object as it "references" the Room object by a string.
Keep in mind that I would like to not implement an Interface or Eventhandlers which I read is basically just a band-aid on the problem and can cause problems in the future.
What you have is effectively a directed graph with cycles. Your model of this is correct - you can't get rid of the cycles.
However, you don't need a separate "Exit" class - you can represent the exits for each room with a List<Room> property called (say) Exits.
Aside: Because the exits are effectively "directed" (i.e. they point to the next room only) to represent a bidirectional exit between room 1 and room 2 you have to add each exit individually. That is, when adding an exit from room 1 to room 2, you must also add an exit from room 2 to room 1 (unless the exits are one-way, of course).
You can use Newtonsoft.Json to serialise and deserialise such a graph, accounting for circular references.
The key thing is that you need to specify the Json serialisation option PreserveReferencesHandling = PreserveReferencesHandling.All.
Another important fact is that you cannot have any constructors that set properties of the class - otherwise the serialisation/deserialisation will fail.
Here's a compilable console app to demonstrate how to do it properly:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ConsoleApp1
{
static class Program
{
public static void Main()
{
var room1 = new Room { Name = "room1" };
var room2 = new Room { Name = "room2" };
var room3 = new Room { Name = "room3" };
room1.Exits.Add(room2); room2.Exits.Add(room1);
room2.Exits.Add(room3); room3.Exits.Add(room2);
room3.Exits.Add(room1); room1.Exits.Add(room3);
var jsonSettings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
var serialised = JsonConvert.SerializeObject(room1, jsonSettings);
var deserialised = JsonConvert.DeserializeObject<Room>(serialised, jsonSettings)!;
Console.WriteLine(deserialised.Name); // "room1"
Console.WriteLine(deserialised.Exits[0].Name); // "room2"
Console.WriteLine(deserialised.Exits[0].Exits[1].Name); // "room3"
}
}
public sealed class Room
{
public string Name { get; init; }
public List<Room> Exits { get; } = new ();
}
}
Note that the printing out of "room3" uses Exits[1] because that's how it was wired up in the first place.
if a exit has no other properties or any properties that a room wouldn't (which I don't know why a exit would be different than a room since a exit would just be a pointer to the next room or null if your at the end of the game) then I would just do this, where the room holds a reference to the next room. Note: This assumes a room has only one exit, if there are multiple see mathews answer.
public class Game
{
public List<Room> Rooms { get; set; }
}
public class Room
{
public int RoomNumber { get; set; }
public Room Exit { get; set; }
}
you can then use it like this
static void Main(string[] args)
{
Game game = new Game();
game.Rooms = new List<Room>();
Room firstRoom = new Room();
Room exit = new Room();
firstRoom.RoomNumber = 1;
exit.RoomNumber = 2;
firstRoom.Exit = exit;
game.Rooms.Add(firstRoom);
foreach(Room room in game.Rooms)
{
Console.WriteLine("Room:" + room.RoomNumber);
Console.WriteLine("Exit:" + room.Exit.RoomNumber);
}
Console.ReadKey();
}
Say I have a dictionary of Something:
private Dictionary<uint, Something> _somethingList = new Dictionary<uint, Something>();
Something being, for example:
class Something
{
public uint Id { get; set; }
public string Name { get; set; }
// ... more stuff here
}
And then I have Another class:
class Another
{
public Another(uint id, string name, Something connection)
{
Id = id;
Name = name;
Connection = connection;
}
public uint Id { get; set; }
public string Name { get; set; }
public Something Connection { get; set; }
}
And using it like this:
var test = new Another(1, "Test", _somethingList[1]);
Will Connection be a reference or copy of the value with key 1 from the _somethingList dictionary or it will create a new memory for it?
I guess what I am asking is, how it would behave in memory, as in, would it duplicate the property data in memory or would it be like a pointer to the actual _somethingList[1]? Or how can I verify this myself(I mean if I break point is there something that indicates whether its a copy or reference or w/e)?
With your data structure and class design, If you perform following line of codes. You will get to know that, in property Connection of Another class you are actually having a reference of _somethingList[1] not a copy.
Editing my Answer with profiler result so you can get the idea of Memory usage too
changed something class (which is just to magnify memory usage and you don't have to consider it in your actual code.
public class Something
{
public uint Id { get; set; }
public string Name { get; set; }
public List<string> stringList { get; set; }
public Something (uint id, string name)
{
Id = id;
Name = name;
stringList = new List<string>();
for(long i = 0; i < 10000; i++)
{
stringList.Add(i.ToString());
}
}
}
and logic is,
DateTime nowDateTime = DateTime.Now;
Dictionary<uint, Something> _somethingList = new Dictionary<uint, Something>();
Console.WriteLine((DateTime.Now - nowDateTime).TotalSeconds.ToString() + " Creating List _somethingList");
//slowly creating lsit so you can get memory usage incresing in profiler
for (uint i = 1; i < 10; i++)
{
_somethingList.Add(i, new Something(i, "amit" + i.ToString()));
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine((DateTime.Now - nowDateTime).TotalSeconds.ToString() + " Before creating test object");
System.Threading.Thread.Sleep(5 * 1000);
Another test = new Another(1, "Test", _somethingList[1]);
Console.WriteLine((DateTime.Now - nowDateTime).TotalSeconds.ToString() + " After creating test object");
Console.WriteLine((DateTime.Now - nowDateTime).TotalSeconds.ToString() + " Name before editing:" + test.Connection.Name);
_somethingList[1].Name = "EditedName";
Console.WriteLine((DateTime.Now - nowDateTime).TotalSeconds.ToString() + " Name after editing:" + test.Connection.Name);
and output is,
you can see, on creating every object of somethingList there is significant increment of memory usage in profiler observation,
but from second 9 to 14, when we are setting reference of _somethingList[1] to Connection there is no memory increasing in profiler result. that means it was just reference setting no memory allocation.
All classes in .net are reference types, therefore you will have a reference to the same dictionary entry and not a copy of it. if you're looking for a copy then use scruct instead of the class. structs are value types but have smaller scope and more limited behavior when compared to classes.
If you in fact need to copy by value and keep the class then you probably can benefit from some deep cloning method and clone you're object before passing onto the constructor. there are numerous implementations of deep and shallow clone out there and you can easily find one online.
There are 2 basic types: Reference and value. Dictionary is not important because you extract a value from Dictionary and pass that.
_somethingList[1] => returns Something object which in turns get's passed to Another.ctor
Think of it as:
Something somethingObj = _somethingList[1];
var test = new Another(1, "Test", somethingObj);
The way these objects behave in memory is a bit tricky. You are working in a managed language which means you don't have direct control over the memory or optimizations.
You can check for identity and equality. Identity means the locations (a location is loosely a memory address with a type) are the same. If two objects have the same identity then they are also always equal. Equality means the values stored in the variables are the same, but the variables themselves may or may not be stored in the same location.
Identity can be checked using Object.ReferenceEquals.
Equality can be checked using Object.Equals.
In this example I show how you can check for identity and equality against Something.
void Main()
{
var a = new Something();
var b = a;
var c = new Something();
Object.Equals(a,b);//True
Object.Equals(b,c);//False
Object.Equals(a,c);//False
Object.ReferenceEquals(a,b);//True
Object.ReferenceEquals(b,c);//False
Object.ReferenceEquals(a,c);//False
var d = M(a);//Pass a to M and check the identity of what comes back
Object.ReferenceEquals(a, d);//True
}
public static Something M(Test e)
{
e.SomeVariable = 10;//a and e now refer to the same object location
//e = new Test();//a and e refer to different objects when you do this. This will not be reflected back to the caller unless you use ref parameters
return e;
}
public class Something { public int SomeVariable {get;set;} }
Again, things get tricky when dealing with optimizations and ref parameters.
New here, I've been learning c# for about a month.
Anyway, I've been searching StackOverflow for a couple of days now and couldn't find a specific answer to my problem...
//Here's my Class
public class Guy
{
public static int ID { get; set; }
public static int LifeExpectancy { get; set; }
public static bool Living { get; set; }
public Guy(int id, int lifeExpectancy, bool living)
{
ID = id;
LifeExpectancy = lifeExpectancy;
Living = living;
}
}
What I'm trying to do is create a specific number of "someGuy" objects to then put them into a public list using this method...
public static List<Guy> Guys = new List<Guy>();
public static void makeSomeGuys(int howManyGuys)
{
for (int i = 0, i <= howManyGuys; i++)
{
int id = i;
int lifeExpectancy = 80;
bool alive = true;
Guys.Add(New Guy(id, lifeExpectancy, alive));
Console.WriteLine("Made a new Guy {0}", id);
}
return;
}
Questions in order of importance:
How do I access a specific object as well as its parameters? (Accessing from the list "Guys".)
How do I access an object from this list in another class? (Not that I absolutely need to, I'm curious)
Can I search for an object in a list by using its parameters? (As opposed to doing something like... humanPopulation[number])
Should I create a new list for objects that have had their parameters modified? (As opposed to leaving it in the original list)
Is it possible to remove items from a list? (Just in general, is that a thing people do? if so, why?)
I really only need the first question answered. The rest of them are just a bonus. Thanks!
First you need to remove the static modifier from the properties of the Guy class, i.e.:
public int ID { get; set; }
public int LifeExpectancy { get; set; }
public bool Living { get; set; }
because static causes the property to be an attribute of the class itself, rather than the instances of the class (the individual 'guys').
To access life expectancy of the first guy (the zeroth):
Console.WriteLine(Guys[0].LifeExpectancy);
To access life expectancy of the fifth guy:
Console.WriteLine(Guys[4].LifeExpectancy);
using System;
using System.Collections.Generic;
using System.Linq;
namespace test
{
public class Guy
{
private int m_ID;
private int m_LifeExpectancy;
private bool m_Living;
public int ID
{
get { return m_ID; }
set { m_ID = value; }
}
public int LifeExpectancy
{
get { return m_LifeExpectancy; }
set { m_LifeExpectancy = value; }
}
public bool Living
{
get { return m_Living; }
set { m_Living = value; }
}
public Guy(int id, int lifeExpectancy, bool living)
{
ID = id;
LifeExpectancy = lifeExpectancy;
Living = living;
}
}
public class MyFactory
{
public IList<Guy> MakeSomeGuys(int howManyGuys)
{
IList<Guy> localGuys = new List<Guy>();
for (int i = 0; i <= howManyGuys; i++)
{
int id = i;
int lifeExpectancy = 80;
bool alive = true;
localGuys.Add(new Guy(id, lifeExpectancy, alive));
Console.WriteLine("Made a new Guy {0}", id);
}
return localGuys;
}
}
public class program
{
public void Main()
{
MyFactory mf = new MyFactory();
IList<Guy> guys = mf.MakeSomeGuys(5);
//How do I access a specific object as well as its parameters? (Accessing from the list "Guys".)
int GetFirstGuyId = guys.FirstOrDefault().ID; //LEARN LINQ
//How do I access an object from this list in another class? (Not that I absolutely need to, I'm curious)
//you need to learn about object oriented encapsulation for better understanding.
//Can I search for an object in a list by using its parameters? (As opposed to doing something like...humanPopulation[number])
Guy guyById = guys.Where(g => g.ID == 5).FirstOrDefault(); // returns the first match (need to learn lambda expression)
//Should I create a new list for objects that have had their parameters modified? (As opposed to leaving it in the original list)
// you need to learn about passing values by value / reference (by reference you already changing the original!).
//Is it possible to remove items from a list? (Just in general, is that a thing people do? if so, why?)
//yes
guys.Remove(guyById);
}
}
}
You're likely new to C# and OO programming, so I've included some good links in this answer.
Regarding question 1 only:
Firstly, your Guy class properties aren't properly encapsulated. Make sure you properly scope the ID, LifeExpectancy and Living properties like shown in this article.
If you'd like to access a specific item, that is, a Guy with a particular ID, you'd be better off using an associative container like Dictionary.
If you're happy with the List container, you need to use the Find method on Guys as shown in the example at the link. You'll notice the term Predicate in the documentation, this link will elaborate.
I have a large collection of automatically generated objects. Although they are all of different, non-related classes, all of the objects share some basic properties (name, id, etc.). I do not control the generation of these objects, so unfortunately I cannot take the ideal approach of implementing an interface. I would like to create a method in which I pass an arbitrary one of these objects and do something using these common properties.
The general idea would be something like:
someObj a = new someObj();
a.name = "sara";
diffObj b = new diffObj();
b.name = "joe";
string phrase = string.Format("I am with {0} and {1}",
getName(a), getName(b));
private string getName(object anyObjWithName)
{
return anyObjWithName.name;
}
though naturally this does not work.
I thought a generic method might hold the answer, but the only way I can see to call it with the current type is using genericMethod.Invoke , which still carries the same issue of not being able to resolve the properties of the passed object in the method. This is unlike Calling generic method with a type argument known only at execution time or How to call generic method with a given Type object? where only the type, or properties of the type, are used in the method, as opposed to properties of the object.
I am aware that this would be (very) prone to error, but I can guarantee that all objects encountered will have the common properties being manipulated.
I can guarantee that all objects encountered will have the common properties being manipulated
If that's the case, you can use dynamic:
private string getName(dynamic anyObjWithName)
{
return anyObjWithName.name;
}
Be aware that using any object that does not have a name property will not fail until run-time.
If you want to add a little bit of safety you can catch the RuntimeBinderException that gets thrown if the property does not exist:
private string getName(dynamic anyObjWithName)
{
try {
return anyObjWithName.name;
}
catch(RuntimeBinderException) {
return "{unknown}";
}
}
If you're unhappy with the performance using dynamic as mentioned by D Stanley, you could always try FastMember.
All you need to know to start using it is pretty much shown in the first 2 code examples.
You are creating a Rube Goldberg device there. You should just have all your data objects classes implement a single interface, then you can work on that. Much simpler and less error prone than fiddling with reflection.
The very fact that a lot of objects have common properties but don't share the same ancestry, on in the very least a common interface, shows that something is wrong with your design. Do rethink it.
Multiple ways to accomplish this, simplest probably is to create Interface and declare common methods there, have your object implement it, then change "getName" method take interface object
private string getName(IMyInterface anyObjWithName)
{
return anyObjWithName.name;
}
The correct way to do this is with an interface, if you own the types that you're working with
public interface IEntity
{
int ID { get; set; }
string Name { get; set; }
}
public class TypeOne : IEntity
{
public int ID { get; set; }
public string Name { get; set }
public string BespokePropertyOne { get; set;}
}
public class TypeTwo : IEntity
{
public int ID { get; set; }
public string Name { get; set; }
public float BespokePropertyTwo { get; set; }
}
static void Main(string[] args)
{
List<IEntity> entities = new List<IEntity>();
entities.Add(new TypeOne() { ID = 1, Name = "Bob", BespokePropertyOne = "blablabla" });
entities.Add(new TypeTwo() { ID = 2, Name = "Alice", BespokePropertyTwo = 5.4f });
foreach (IEntity entity in entities)
{
Console.WriteLine("ID: {0} Name: {1}", entity.ID, entity.Name);
}
}
This answer was written before the edit to the question stating that interfaces weren't possible in this case. Perhaps it can help someone else reading this question.
Interface:
interface Iname
{
string Name { get; set; }
}
Use interface:
class A : Iname
{
public string Name { get; set; }
}
class B : Iname
{
public string Name { get; set; }
}
The method:
string GetName(Iname o)
{
return o.Name;
}
Use:
A a = new A { Name = "First" };
B b = new B { Name = "Last" };
Text = GetName(a) + " " + GetName(b);
This is probably a simple question. Suppose I have a object called Users and it contains a lot of protected variables.
Inside that Users class I have a method that creates a temporary Users object, does something with it, and if successful, transfers all the variables from the temp Users object into the one I have.
Is there some fast way to transfer all the variables from one Users object into another Users object without doing this using C#?
this.FirstName = temp.FirstName;
this.LastName = temp.LastName;
........75 variables later......
this.FavoriteColor = temp.FavoriteColor
A better approach is to implement the IClonable interface. But you'll find it doesn't save you a lot of work.
You should check out cloning in C#.
Deep cloning objects
I think serializing and then deserializing an object will create a new object instance. This should be identical to the former object.
A better solution might be to move whatever this method is outside of your class, and then just assign the temp user object to your main user object reference like so:
_User = tmpUser;
sparing you the 75 lines of code. Whenever I have a class creating an instance of itself inside one of its own methods, I always like to blink a couple of times and make sure I really need to be doing that.
There's always the reflection option. Something substantially similar to this:
public static void Copy(object source, object target)
{
foreach (System.Reflection.PropertyInfo pi in source.GetType().GetProperties())
{
System.Reflection.PropertyInfo tpi = target.GetType().GetProperty(pi.Name);
if (tpi != null && tpi.PropertyType.IsAssignableFrom(pi.PropertyType))
{
tpi.SetValue(target, pi.GetValue(source, null), null);
}
}
}
Doesn't require the source and the target to have any relation what-so-ever, just a name and an IsAssignable check. It has the interesting side effects if you're using reference types anywhere, but for the kind of situation you just described, this isn't a bad option to explore.
class sourceTester
{
public bool Hello { get; set; }
public string World { get; set; }
public int Foo { get; set; }
public List<object> Bar { get; set; }
}
class targetTester
{
public int Hello {get; set;}
public string World { get; set; }
public double Foo { get; set; }
public List<object> Bar { get; set; }
}
static void Main(string[] args)
{
sourceTester src = new sourceTester {
Hello = true,
World = "Testing",
Foo = 123,
Bar = new List<object>()
};
targetTester tgt = new targetTester();
Copy(src, tgt);
//Immediate Window shows the following:
//tgt.Hello
//0
//tgt.World
//"Testing"
//tgt.Foo
//0.0
//tgt.Bar
//Count = 0
//src.Bar.GetHashCode()
//59129387
//tgt.Bar.GetHashCode()
//59129387
}