My primary languages growing up were PHP, Python, etc. In these languages it is very easy to initialize dictionary-style objects (so-called associative arrays in other languages).
I am using C# for a project now and find the method of initializing a large dictionary to be quite cumbersome and figured I may be doing something wrong, or against best practices. For example, here is a dictionary I want to keep some project data in:
//Campaign dictionary
public Dictionary<int, Dictionary<string, Dictionary<object, Dictionary<string, object>>>> campaignData = new Dictionary<int, Dictionary<string, Dictionary<object, Dictionary<string, object>>>>();
It seems like there is a better way to do this. The code is not readable at all and just to initialize a simple 3-4 stage hierarchy is a massive line of code. If you know of a way, please let me know! Thank you
EDIT ** I have drawn out the type of structure I am trying to obtain. Game progress data that can be bundled and written to a save file:
Don't use dictionaries for everything. A dictionary is essentially a collection of values or objects identified by unique keys. Unless that's specifically what you're using, a dictionary is the wrong tool.
Instead, consider the semantics of the structure you want and build that structure. For example, in the image in the question you have:
An Objective, which contains a Vector3 and a bool
A list of Objectives
A Level, which contains a list of Objectives and a bool
So something like this:
public class Objective
{
public Vector3 Position { get; set; }
public bool IsCompleted { get; set; }
}
public class Level
{
public IEnumerable<Objective> Objectives { get; set; }
public bool LevelIsComplete { get; set; }
}
Maybe you further have a list of levels, contained perhaps within a "game" or something of that nature. Etc.
The point is that C# embraces static typing in classes, where you're trying to use very loose typing in associative arrays. Build the structures you want into classes, include the necessary logic within those classes where that logic semantically belongs, and the code will read a lot better.
I never encountered such a multi-level map structure but if you want to do it cleaner, you need to define those map structures as types. This makes the code both readable (in terms of declaration length) and understandable.
Of course you would use sensible names for the types and not TypeOutermost.
internal class Program
{
public static void Main(string[] args)
{
var campaignData = new Dictionary<int, TypeOutermost>();
}
public class TypeOutermost : Dictionary<string, TypeMid>
{
}
public class TypeMid : Dictionary<object, TypeInnermost>
{
}
public class TypeInnermost : Dictionary<string, object>
{
}
}
Related
I'm attempting to deserialize the pokemon API located at https://pokeapi.co/api/v2/pokemon/3 and I'm relatively new to working with json. I've made a class and method that loads whatever pokemon I choose into an object but can only get it to work with the simple keys like "name: value" and "id: value"
class Pokemon
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
// [JsonProperty("abilities")]
// public Dictionary<string, string>[] Abilities { get; set; }
//[JsonProperty("types")]
// public Dictionary<string, int>[] Types { get; set; }
//[JsonProperty("sprites")]
//public Dictionary<string, string> Sprites { get; set; }
public static Pokemon LoadPokemon(int num)
{
string json = new WebClient().DownloadString($"https://pokeapi.co/api/v2/pokemon/{num}");
Pokemon pokemon = JsonConvert.DeserializeObject<Pokemon>(json);
return pokemon;
}
}
All of the fields I can't make work I've commented out. Basically my question is how do I make those fields I've commented out actually load. I've tried a combination of dictionaries, arrays, and lists as datatypes but I can't seem to make anything work.
"sprites": {
"back_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/3.png",
"back_female": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/female/3.png",
"back_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/3.png",
"back_shiny_female": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/back/shiny/female/3.png",
"front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png",
"front_female": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/female/3.png",
"front_shiny": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/3.png",
"front_shiny_female": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/female/3.png",
"other": {
"dream_world": {
"front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/dream-world/3.svg",
"front_female": null
},
"official-artwork": {
"front_default": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/3.png"
}
},
'Unexpected character encountered while parsing value: {. Path 'sprites.other', line 1, position 189387.' This is my usual error message when I attempt to load sprites, and the other attributes have similar errors. I can see why the "other:" key wouldn't work with Dict<string, string> but I also don't know how to avoid that problem since not every key in sprites has that format.
Also I'm using NewtonSoft.Json and System.Net packages. You can find the abbreviated version of the API at https://pokeapi.co/.
Trying to figure out the correct C# structure for very complex JSON documents can be quite difficult. I would suggest you start by using one of the many online JSON to C# convertor tools (e.g. https://app.quicktype.io/ or Google "JSON to C#") to take a sample JSON document and generate your class models. Using the sample JSON from https://pokeapi.co/, I used the quicktype tool to instantly generate the C# models. You can then take that C# code and modify it to suit your needs (create separate files for each class, remove unneeded properties, etc). But at least this provides you with a good (and valid) starting point. Tools like quicktype have config options that allow you to to refine the models, such as if you want JSON arrays to be C# arrays or Lists, etc.
"sprites" in your example will resolve to a Dictionary<string, object>. You will then, in your code, have to cast the value to either string, or another Dictionary<string, object> in the case of "dream_world" and "official_artwork".
I'm making a Phone Book console application in c# and It's my biggest project so far :)
I consider myself as a beginner but I would love to improve
I am using 3 classes to create this, here they are:
Modifications
Search
Display
Modifications class is responsible for adding, deleting and editing contacts. Search and Display classes are self explanatory. I also have interfaces for each of these classes.
Problem:
I created a List of KeyValuePair inside Modifications class, like this:
private List<KeyValuePair<string , int>> AllContacts { get; set; }
public Modifications()
{
AllContacts = new List<KeyValuePair<string, int>>();
}
I would like to access this AllContacts object in my other classes. But I failed to achieve this while maintaining encapsulation. AllContacts is like my main source of data. I add contacts in this List. I don't want someone in my main method to be like modificationObject.AllContacts.Clear();
My Attempts:
[ skip this if you prefer :) ]
My Sad Attempt Part 1:
-Inherited Display Class from base class Modifications
-in my Modifications class, I created a protected property of type List<KeyValuePair<string , int>> and named it 'AllContacts' as a database
-in my Display class , I created a private property of same type as above and named it _allContacts
-inside Constructor of my Display class, I requested a Modification type object named it modObject
-I stated , _data = modObject.AllContacts;
-It didnt work, I presume it's because only derived objects are able to get this property?
My Sad Attempt Part 2:
-Assuming my assumption is true, I tried to downcast the modObject to its derived class type, Display. Got compilation error instead. Tried to make a protected GetAllContacts() method, compilation error.
My Sad Attempt Part 6:
-In end, I just made it a public property with a private setter. My application works, But people could still go x.AllContacts.Clear() in my main method somehow.
Questions:
How can I use AllContactsobject in other classes without breaking encapsulation? Is it even possible?
Initially, I created a separate class for data and I had 3 other classes (Modification, Search and Display) , its a better design, right? I had same problem in accessing that data object in my other classes.
Thanks :)
Additional Context if required: (currently working application , no methods)
Modification class:
public class Modifications
{
public List<KeyValuePair<string, int>> AllContacts { get; private set; }
public Modifications()
{
AllContacts = new List<KeyValuePair<string, int>>();
}
....
Display class:
public class Display : IDisplayable
{
private List<KeyValuePair<string, int>> AllContacts;
public Display(Modifications modificationsObject)
{
AllContacts = modificationsObject.AllContacts;
}
....
You don't need to declare accessors for a private variable member unless you want to disallow the setter for all others methods but it is more speed optimized to use readonly field than property that avoid useless CPU Proc Calls that consume ticks timings for nothing.
To access it from other classes you must declare it as public like that:
public List<KeyValuePair<string , int>> AllContacts { get; private set; }
So others classes can read the reference and invoke variables accessors and methods of the List instance like Count and Add but they can't replace this instance reference and thus change the object itself.
But if you want to disallow manipulating of the list, you may implement all wrapped methods you want to expose like Count, Add, Delete, Remove and so on as well as indexer and you can indicate that the class implements IExumerable<KeyValuePair<string , int>>.
By this way you can have a strong encapsulation:
public class MyClass: IEnumerable<KeyValuePair<string , int>>
{
private readonly List<KeyValuePair<string , int>> AllContacts
= new List<KeyValuePair<string , int>>();
public int ContactsCount
{
get { return AllContacts.Count; }
}
public KeyValuePair<string , int> this[int index]
{
get { return AllContacts[index]; }
set { AllContacts[index] = value; } // don't declare if readonly
}
// if adding is allowed
public int Add(KeyValuePair<string , int> item)
{
...
}
...
}
I want to create a nested structure where every class represents a country, inheriting the same parent class Country. Each child class should have an enum representing the different states States.
The goal is being able to select a country, then one of its states.
The Content will be saved into a dictionary Dictionary<Tuple<string, Type>, object> where the Types would be Country and Country.States.
I tried making an interface/abstract class with an enum called States to be implemented, but this does not work, as it is a type definition.
Is there any workaround?
public abstract class Country
{
public abstract enum States { get; }
}
public class CountryA : Country
{
public new enum States
{
StateA,
StateB,
StateC,
}
}
Your design is flawed, you need to create a single Country class with a property e.g. public string[] States { get; set; }.
Then create instances (objects) of your Country class, each with States set to the items that are needed:
var usa = new Country { Name = "USA", States = new[] { "Alabama", ... } };
var canada = new Country { Name = "Canada", States = new[] { ... } };
// etc
You have a few options:
You can create an enum at runtime (see here: Dynamically create an enum), but I don't think that'll suit your needs, as I imagine you're going down the enum route for ease of use in coding than anything else.
You could implement a typesafe enum pattern (see here: typesafe enum pattern), but that's even more coding just for the ability to use a design that mimics enums while your coding the rest of your logic.
My advice is to use a dictionary and build your 'states' at instantiation from a settings file or external data source. After all, countries and their states/cities/etc do change names from time to time. Locking yourself into a hard-coded situation like what you're aiming for isn't going to support such future changes.
Good luck!
[Edited following response from camilo-terevinto]
While I certainly agree that your design is most likely flawed, since you'd need hundreds of classes and enums, I disagree entirely with the other answers that "it is not possible".
It's certainly possible using generics (while keeping in mind you cannot restrict entirely to Enums):
public abstract class Country<TStates>
where TStates: struct, IConvertible, IFormattable, IComparable
{
public abstract TStates[] States { get; }
}
public enum UnitedStatesStates
{
WhoCares, WhoCares2
}
public class UnitedStatesCountry : Country<UnitedStatesStates>
{
public override UnitedStatesStates[] States { get; }
}
Now, I highly doubt this will be useful in the (not-so-long) term.
You are asking to make enum inheritable, this is possible to achieve if you don't use enum, but a class with static public members (which can be inherited and have different set of members per type). It behave nearly as enum:
public class Country1
{
public static State State1 { get; } = new State("State 1");
public static State State2 { get; } = new State("State 2");
...
}
It should be clear what Country1.State1 is, right? The State can be a more complex object than just a string. It doesn't require inheritance as you can see, because country define states as different members.
You can follow same principle to implement long chain of objects: Planet.Continent.Country.State.Province.Town.Street.Hause..
You say
Content will be saved into a dictionary Dictionary<Tuple<string, Type>, object> where the Types would be Country and Country.States.
Don't. Those are different types, that's a poor choice of a key. If you need to enumerate (to find) states, then just add another member to a Country:
public static IEnumerable<State> States
{
get
{
yield return State1;
yield return State2;
...
}
}
Then the searching for something can be a simple linq:
var stateAInCountry1 = ...Countries.OfType<Contry1>().Single().States.Single(o => o.Name == "A");
var countriesWithStateA = ...Countries.Where(o => o.States.Any(o => o.Name == "A"));
Not sure what problem are you solving by introducing a dictionary, but you can initialize additional data structure with proper key if you provided a way to iterate with easy.
It is not so clear to me, if there is anything else you want to achieve, besides being reminded by the compiler to define these different (!) enums.
Actually they have nothing in common to begin with, so neither the compiler nor you can draw any advantage of that contract.
What you could do is declare it as
public abstract string[] States {get;}
and obtain these strings from the individual enums you define in the derived classes. Then the common thing would probably be that you want the string result for informative purposes or something.
I have a class which contains a lot of Lists:
private List<MyClass> m_List1;
private List<MyClass> m_List2;
private List<MyClass> m_List3;
private List<MyClass> m_List4;
...
private List<MyClass> m_ListN;
Everything is ok, but code is somehow getting complicated to read and to write... especially when I need to instanciate those lists when needed or clear them all.
Can you suggest me a good and elegant solution to manage them better? I was thinking about a Dictionary<String, List<MyClass>> that can act as a kind of "wrapper" for all my lists or, even better, a class with an internal Dictionary<String, List<MyClass>> that exposes a method ClearAll(), for example...
In that case, how should I deal with list replacements, clearing, disposing and so on? Let's say I have the following code in my wrapper...
public void Assign(String key, List<MyClass> value)
{
m_InternalDictionary[key] = value;
}
If another list already exists on that key, should I clear it before replacing it with another one?
Any other suggestion?
Is there any reason why you need to have separate lists? Why not just have a member in your class that is a list of lists?
private List<List<MyClass>> myClasses { get; set; }
I want to have a large number of class instances return the same similar fields of data, like in this example implementation:
foreach (SomeClass sc in SomeClasses)
{
System.Console.WriteLine(sc.GetData("1st field"));
System.Console.WriteLine(sc.GetData("Another field"));
System.Console.WriteLine(sc.GetData("and another"));
}
// ---- inside SomeClass:
Dictionary<string, string> myData;
public string GetData(string field)
{
return myData[field];
}
What I don't like is the string hashing, lookup and matching that has to happen over and over again in the example (I assume thats how Dictionary works). I would really like to find a better approach.
Coming from the C world, I thought of assigning all fields a unique integer key, such that I can change into an array lookup:
// ---- inside SomeClass:
string[] MyData;
public string GetData(int field_key)
{
return MyData[field_key];
}
Now the field lookup is efficient, but it just doesn't feel right in these "arrays are evil" times, and it is tedious and error prone to deal with the field_key integer.
I don't know if I'm chasing performance ghosts here, its just that I want to find a design that is both efficient and clean.
Suggestions?
Why don't you want a dictionary look-up? A very efficient implementation of a dictionary would be an index look up of the hash in an array. So the underlying implementation could boil down to the code in your second example. This would make it O(1)
Use the Dictionary
Because the fields are not known at compile time, but rather dynamic and user configurable, I'm going to modify your example program slightly to use an array of properties. Then I'd advocate an approach similar to yours but using your own custom class (here, called MyProperty) rather than string. Performance will be at least as good as (and maybe a tad better than) the string approach, but the benefit is that it gives you more flexibility: if you ultimately decide for performance reasons that you need to use an array or List approach, you can easily embed an array index into your MyProperty class. You'd have to change the implementation of GetData but not your calling code.
public static void Test1() {
SomeClass[] SomeClasses; //created somehow
//in real life, this would be determined dynamically
var properties=new[] {SomeClass.FirstField, SomeClass.AnotherField, SomeClass.AndAnother};
foreach(var sc in SomeClasses) {
foreach(var property in properties) {
Console.WriteLine(sc.GetData(property));
}
}
}
public class SomeClass {
public static readonly MyProperty FirstField=new MyProperty();
public static readonly MyProperty AnotherField=new MyProperty();
public static readonly MyProperty AndAnother=new MyProperty();
private readonly Dictionary<MyProperty, string> myData=new Dictionary<MyProperty, string>();
public string GetData(MyProperty property) {
return myData[property];
}
}
//default implementation of Equals and GetHashCode are fine here
public class MyProperty {}
HOWEVER, since your target application is really about collecting a set of dynamic and user configurable property getters, maybe you really want to make some Funcs? Code like the below will be very fast, and it still has the ability you want, namely it allows you to make a little dynamic, user-configurable list of property getters.
public static void Test2() {
SomeClass[] SomeClasses; //created somehow
//in real life, this would be determined dynamically
var getters=new[] {SomeClass.FirstField, SomeClass.AnotherField, SomeClass.AndAnother};
foreach(var sc in SomeClasses) {
foreach(var getter in getters) {
System.Console.WriteLine(getter(sc));
}
}
}
public class SomeClass {
public static readonly Func<SomeClass, string> FirstField=sc => sc.field0;
public static readonly Func<SomeClass, string> AnotherField=sc => sc.field1;
public static readonly Func<SomeClass, string> AndAnother=sc => sc.field2;
private string field0;
private string field1;
private string field2;
}
If your instances have the same fields, why not just use properties?
foreach (SomeClass sc in SomeClasses)
{
System.Console.WriteLine(sc.FirstField);
System.Console.WriteLine(sc.AnotherField);
System.Console.WriteLine(sc.AndAnother);
}
First, if you're not sure this actually is a performance problem for you, then yes, you are chasing performance ghosts and your current implementation is fine.
But if you found out during profiling that you really need to make this code faster, then your seems fine. “Arrays are evil” is mostly true only in public interfaces, it's fine to use them for implementation.
One thing I would change about your code though: create an enum containing the fields and use that instead of int. It's just as fast and much more readable. If the fields are not known at compile time, using int is fine. If you do know some of the fields at compile time, you could use static properties for them.