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();
}
Related
In Haskell you can create a new datatype for example as follows:
Player = Player1 | Player2
And further in your code you can check whether it's Player1 or Player2 by just typing Player1 and not some strange with like "Player1" that it has to be a String or check with an integer.
Is something similar possible in C#?
I can only think of:
class Player
{
public int CurrentPlayer { get; private set; }
public Player(int plyr)
{
CurrentPlayer = plyr;
}
}
But now I can't check with just thisplayer = Player1 (if thisplayer is a Player).
Eventually this sort of means: How can you create your own object that can only have an already defined finite amount of values, for example like Bools?
Use Enums:
using System;
public class Program
{
private enum Player { PlayerOne, PlayerTwo }
public static void Main()
{
Player player = Player.PlayerTwo; // Change me between Player.PlayerOne and Player.PlayerTwo to see the output change.
switch(player)
{
case Player.PlayerOne:
//this will get executed
Console.WriteLine("Player is Player One!");
//do stuff
break;
case Player.PlayerTwo:
//this will not get executed
Console.WriteLine("Player is Player Two!");
//do stuff
break;
default:
//this will not get executed
break;
}
}
}
Output:
Player is Player Two!
See for yourself on .NET Fiddle
Enums are a way to create a somewhat-strongly-typed set of aliases for integers. However, you can always cast an integer (of whatever type you specified for your enum, by default int) to the enum type, so you have to trust the code to not do that (which might be acceptable for an internal enum type). Additionally, you can't add any additional information to the enum value itself; any time you interpret the value, you have to use a switch or similar construct.
If you want to actually have a class with properties and such, but want to restrict the number of instances of that class, you can extend the singleton pattern like this:
sealed class Player
{
// Properties that a Player object has, an improvement over using an enum
// which don't allow you to specify properties.
public int Number { get; }
public bool IsHost { get; }
// This constructor is private, so only the code inside the Player class may create a Player object
// (notwithstanding reflection, etc., which are outside the rules of static typing).
private Player(int number, bool isHost)
{
Number = number;
IsHost = isHost;
}
// Static properties provide singleton instances of Player for each player number.
public static Player One { get; } = new Player(1, true);
public static Player Two { get; } = new Player(2, false);
public static Player Three { get; } = new Player(3, false);
public static Player Four { get; } = new Player(4, false);
}
And then use it like this:
void Main()
{
SomethingThatTakesPlayer(Player.Three);
}
void SomethingThatTakesPlayer(Player p)
{
Console.WriteLine($"Player #{p.Number} is the host? {p.IsHost}");
}
Hi guys I need some help. I'm completely suck on how to do this with Inheritance.
The aim is to change the value of 'Name' property inherited by the Parent Class (Clothing) of a shirt object. When a button is clicked withing my C# Web Form by calling the Shirt's method of "ReNameShirt()" to change the name and then display the new 'name'.
My teacher hinted me by saying to use a subroutine. Still lost.
Can you help me out? Much Appreciated.
Clothing Class
using System;
//THE PARENT CLASS 'Clothing'
public class Clothing
{
public string _name;
public string _size;
public string name {get; set;}
public string size {get; set;}
}
//SUBCLASS OF 'Trousers'
public class Trousers : Clothing
{
public string LegLength { get; set; }
public Trousers()
{
LegLength = "91";
}
}
public class Shirt : Clothing
{
public string ReNameShirt()
{
Shirt Po = new Shirt();
Po.name = "blue shirt";
return ReNameShirt();
}
within the Inheritance.aspx.cs file:
protected void Button2_Click(object sender, System.EventArgs e)
{
Shirt myShirt = new Shirt();
myShirt.name = "red polo";
myShirt.size = "85";
Label2.Text = "<b>Name:</b> " + myShirt.name + " <b>Size</b> " + myShirt.size;
myShirt.ReNameShirt();
Label3.Text = myShirt.size;
}
}
Your shirt already exists so there is no need for you to create an instance of it. Doing that isn't modifying "this shirt." It's like if you told me "dye this shirt blue" and instead I said "here is another blue shirt" but then threw it away (because the variable goes out of scope). Your next problem is you are doing recursion. Since it sounds like you're new to programming, let me explain. Recursion is when a method (what your professor is calling a subroutine, another term for it) calls itself. That's OK, but you need it to end at some point. In your case, your method will call itself until you overflow the stack (get it... stackoverflow?) and the program can't make any more calls so it will crash. When ever you do recursion, you need to make sure there is a way to end it. Classic recursion problems are like factorial where it is defined as n*(n-1) factorial, but the way it ends is 1! Is just defined as 1, so once n-1 =1, I don't factorial any more, I just return 1.
public class Shirt : Clothing
{
public void ReNameShirt()
{
// Shirt Po = new Shirt(); You are a shirt, there is no need to create one.
name = "blue shirt";
// return ReNameShirt(); This will cause infinite recursion and crash.
}
Your ReNameShirt method isn't doing what you thing it's doing. It's instantiating a new Shirt and will cause recursion rather than changing the shirt's name. Change it to:
public void ReNameShirt()
{
this.name = "blue shirt";
}
Your problem is that you are creating a new instance inside your method and updating the value of this instance.
Your function should be something like that:
public class Shirt : Clothing
{
public void ReNameShirt()
{
name = "blue shirt";
}
}
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.
I am using AutoMapper to convert a UI model to POCOs that I later serialize to XML using a DataContractSerializer in order to preserve the references between them.
The problem comes that, when mapping, the references between those entities are lost.
The UI classes reference each other, but the mapping process makes new instances for every reference, so the original relations are broken :(
Let me explain:
I have 2 entities of type Person
Person
{
List<House> OwnedHouses
}
And these 2 objects
John
who owns
House1
Will
who also owns
House1
When AutoMapper maps each Person correctly, but when it also maps House1 as two different instances!!
So I have a two copies of House1. John owns his House1 (#1) and Will owns his House1 (#2).
They are not linked anymore.
Is there any way to keep the relations that originally existed?
Thanks.
EDITED: Actually what I have is this:
A Document contains a list of ChildDocuments. Each ChildDocument has a list of Designables (Rectangles, Lines, Ellipses…) and a especial designable called ChildDocumentAdapter that contains itself ANOOTHER ChildDocument. This is the trouble, it can reference another ChildDocument.
If I'm understanding the question, you're performing two separate mapping operations - one for John, another for Will.
#Sunny is right. AutoMapper is not designed to do this. Each call you make to Mapper.Map() is typically independent of any other. By using the same instance of the HouseListConverter, you get the benefit of caching all mapped houses in a dictionary. But you have to either register it globally or pass it as an option to the mapping calls you want grouped together. That's not just extra work, it's hiding a very important implementation detail deep within the converter.
If you map both John and Will in one operation, by putting them into a collection, the output would be what you want without the need for a custom converter or resolver.
It may be an easier alternative for other people with a similar problem.
public void MapListOfPeopleWithSameHouse()
{
Mapper.CreateMap<Person, PersonDTO>();
Mapper.CreateMap<House, HouseDTO>();
var people = new List<Person>();
var house = new House() { Address = "123 Main" };
people.Add(new Person() { Name = "John", Houses = new List<House>() { house } });
people.Add(new Person() { Name = "Will", Houses = new List<House>() { house } });
var peopleDTO = Mapper.Map<List<PersonDTO>>(people);
Assert.IsNotNull(peopleDTO[0].Houses);
Assert.AreSame(peopleDTO[0].Houses[0], peopleDTO[1].Houses[0]);
}
While Automapper is not designed with this in mind, it's powerful enough to let you do it, using custom type converters. You need to create your own converter from IList<House> to IList<HouseDto>, and inject it using a factory:
using System;
using System.Collections.Generic;
using AutoMapper;
using NUnit.Framework;
using SharpTestsEx;
namespace StackOverflowExample
{
public class House
{
public string Address { get; set; }
}
public class Person
{
public IList<House> OwnedHouse { get; set; }
}
public class HouseDto
{
public string Address { get; set; }
}
public class PersonDto
{
public IList<HouseDto> OwnedHouse { get; set; }
}
[TestFixture]
public class AutomapperTest
{
public interface IHouseListConverter : ITypeConverter<IList<House>, IList<HouseDto>>
{
}
public class HouseListConverter : IHouseListConverter
{
private readonly IDictionary<House, HouseDto> existingMappings;
public HouseListConverter(IDictionary<House, HouseDto> existingMappings)
{
this.existingMappings = existingMappings;
}
public IList<HouseDto> Convert(ResolutionContext context)
{
var houses = context.SourceValue as IList<House>;
if (houses == null)
{
return null;
}
var dtos = new List<HouseDto>();
foreach (var house in houses)
{
HouseDto mapped = null;
if (existingMappings.ContainsKey(house))
{
mapped = existingMappings[house];
}
else
{
mapped = Mapper.Map<HouseDto>(house);
existingMappings[house] = mapped;
}
dtos.Add(mapped);
}
return dtos;
}
}
public class ConverterFactory
{
private readonly IHouseListConverter resolver;
public ConverterFactory()
{
resolver = new HouseListConverter(new Dictionary<House, HouseDto>());
}
public object Resolve(Type t)
{
return t == typeof(IHouseListConverter) ? resolver : null;
}
}
[Test]
public void CustomResolverTest()
{
Mapper.CreateMap<House, HouseDto>();
Mapper.CreateMap<IList<House>, IList<HouseDto>>().ConvertUsing<IHouseListConverter>();
Mapper.CreateMap<Person, PersonDto>();
var house = new House {Address = "any"};
var john = new Person {OwnedHouse = new List<House> {house}};
var will = new Person { OwnedHouse = new List<House> { house } };
var converterFactory = new ConverterFactory();
var johnDto = Mapper.Map<PersonDto>(john, o=>o.ConstructServicesUsing(converterFactory.Resolve));
var willDto = Mapper.Map<PersonDto>(will, o=>o.ConstructServicesUsing(converterFactory.Resolve));
johnDto.OwnedHouse[0].Should().Be.SameInstanceAs(willDto.OwnedHouse[0]);
johnDto.OwnedHouse[0].Address.Should().Be("any");
}
}
}
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
}