Count depth of a hierarchy of classes - c#

I've seen a lot of different examples of how to do this and am well aware that I could write out a loop that iterates my entire tree of classes to find the maximum depth, but I cannot help but think there has to be a simpler way.
Basically I have two classes that I developed to host all my applications settings, SettingGroup which is exactly what it sounds like, basically a folder, and Setting which is the setting itself and the configurations that allow the application to know what the setting is for and how to display it. The reason I dont just use a fixed class and write out field for my settings is that the application is plugin driven and I wish the settings to remain centralized is plugins are added or removed and not have to worry about decentralized data from the plugins.
When dynamically creating the settings page it is necessary to know the maximum depth of any particular SettingGroup so I know if the root should first organized by tabs, pages, sections etc...
Long story short, is there a reasonably lightweight way to determine the groups maximum depth?
public enum DescriptionVisibility { None, SubText, ToolTip };
public enum SettingType { Bool, Integer, Decimal, Text };
public enum SettingControl { Checkbox, Textbox, Slider, Radio, Dropdown, TextField, Color};
public class SettingGroup
{
public string name { get; set; }
public string description { get; set; }
public List<SettingGroup> groups { get; set; }
public List<Setting> settings { get; set; }
}
public class Setting
{
public string name { get; set; }
public string description { get; set; }
public DescriptionVisibility descriptionVisibility { get; set; }
public Dictionary<string, dynamic> configuration { get; set; }
public dynamic settingValue { get; set; }
public SettingType settingType { get; set; }
public SettingControl settingControl { get; set; }
}
Edit: this is untested, but this is what I am currently considering using;
private static int getDepth(this SettingGroup group, int depth = 0)
{
if (group.groups == null)
return depth;
if (group.groups.Count == 0)
return depth;
int returnDepth = depth;
foreach (SettingGroup subGroup in group.groups)
{
int subGroupDepth = subGroup.getDepth(depth + 1);
if (subGroupDepth > returnDepth)
returnDepth = subGroupDepth;
}
return returnDepth;
}
Its pretty basic so it couldn't be TOO slow, but still seems bulky, is there not a LINQ way to do this perhaps?

Related

.net6 dynamic option choices with Lists?

I am building a character creator for an out-of-print TTRPG system. The issue that I've run into is how to dynamically create dropdown boxes where the user can make skill/weapon choices based on their race/class choice.
For example: If user picks raceOne, he may pick any Lore skill he wants(he can do this twice), and he may choose one of any profession.
Now, Race two has some more interesting choices: He needs to pick between skillId 5 or SkillId 6, he also needs to make a decision between skillId 7 or 8.
My initial thought was to create a multi-dimensional array, and have array[x][] represent the number of choices one would have to make (RaceTwo in this example, has 2 different choices to make.) and choice[0][x] would represent one of the options. and then in my view I could just iterate through the array to create the dropdowns and their options, but it appears that arrays cannot be sized dynamically in c#.
Attached here is my RaceEntity, and the StartingSKills entity. I dont know enough about what I'm doing to know exactly what all code I should post here, but I'm trying to learn.
public class Race
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string? ImagePath { get; set; }
public virtual IList<RaceStartingArmor> RaceStartingArmor { get; set; }
public virtual IList<RaceStartingSkills> RaceStartingSkills { get; set; }
public virtual IList<RaceStartingTalents> RaceStartingTalents { get; set; }
public virtual IList<RaceStartingWeapons> RaceStartingWeapons { get; set; }
public virtual IList<RaceStartingGear> RaceStartingGear { get; set; }
}
public class RaceStartingSkills
{
public RaceStartingSkills(int RaceId, int SkillId , bool isKnown)
{
this.RaceId = RaceId;
this.SkillId = SkillId;
this.isKnown = isKnown;
}
public int Id { get; set; }
[ForeignKey(nameof(Race))]
public int RaceId { get; set; }
public Race Race { get; set; }
[ForeignKey(nameof(Skill))]
public int SkillId { get; set; }
public Skill Skill { get; set; }
public bool isKnown { get; set; }
public bool isTrained { get; set; }
public bool isSkilled { get; set; }
public bool isExpert { get; set; }
}
some more context: After race/class is chosen, the user is taken to a view where both race and class options are to be populated and chosen, this DTO will then be sent to the character sheet view and populated
any information, or video links, or anything just to get me moving in the right direction would be exceptionally helpful.

Creating class members during run time - C#

I have a simple class defined like this:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
}
In the code, I get some data as list<double> perfdepth; assume this is perfdepth1,perfdepth2,perfdepth3. Of course, this list is dynamic hence, I wouldnt know beforehand to change my class definition to:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
public double perfdepth1 { get; set; }
public double perfdepth2 { get; set; }
public double perfdepth3 { get; set; }
}
Can these new members be created during run time?
The reason why I think I would need this is because of data binding in WPF. Eventually I need to display "point series"; Perfdepth1 as one series, perfdepth2 as another series and so on, i.e, dynamic number of Perfdepths.
If there is a simpler way to do it, I am all ears!
You might just want to use the dynamic type with ExpandoObject..
dynamic stickColumns = new ExpandoObject();
stickColumns.wellName = "Something";
stickColumns.perfdepth1 = "Something Else";
It has its drawbacks as it does mean you end up with runtime errors etc... but it can be useful for this type of scenario.

MVC design pattern for multiplatform lib

I currently have a design problem currently on a personal project, I'm developing both an Android app (using xamarin) and a C# wpf windows application.
The application on desktop help the user to design some exercices that the student on the android app can practice. But currently, I want to have a good structure for the code, by principally having a common lib to both apps. The problem is, following the MVC design pattern, everything in my model should be independent from the view. Or, on Android I need to keep track when an exercise is running, and what button the student pressed. Or this kind of information is not saved after the exercise is done, and from the windows app point of view it's useless information. So in this case should I write a kind of wrapper around my model for the android app so I can save this data ? It seems that doing this way is going against the MVC pattern, but I can't find a solution to this. To better illustrate my problem here is my model :
public class File
{
public string Name { get; set; } = "file";
public List<Module> Modules { get; set; } = new List<Module>();
}
public class Module
{
public string Title { get; set; } = string.Empty;
public string Color { get; set; } = "0xFF0000";
public List<Exercice> Exercices { get; set; } = new List<Exercice>();
}
public class Exercice
{
public string Name { get; set; } = string.Empty;
public List<string> Sounds { get; set; } = new List<string>();
public List<Unit> Units { get; set; } = new List<Unit>();
public bool Randomize { get; set; } = false;
}
public class Unit
{
public string Text { get; set; } = string.Empty;
public List<string> Sounds { get; set; } = new List<string>();
public EType Type { get; set; }
public bool Solution { get; set; } = true;
public List<UnitChild> Units { get; set; } = new List<UnitChild>();
}
public class UnitChild
{
public string Text { get; set; } = string.Empty;
public List<string> Sounds { get; set; } = new List<string>();
public EType Type { get; set; }
public bool Solution { get; set; } = true;
}
public enum EType
{
Touch,
Display,
Voice
}
Everything is loaded and parsed from a YAML file, because I need this to be really structured.
In each of this class, I don't want to keep (in Unit and UnitChild classes) which one has been pressed, because it's superfluous and maybe need to be saved in the controller (which I currently didn't wrote, since I want to figure this out before the actual coding). Basically, all the fields are the core of the exercices, and is the only data needed for the Windows app.
Thanks for your help !
I hope this does not look messy
I figured this out by myself,
While reading documents on MVC design pattern, and more specific articles on C# WPF programming.
If you're in my situation, what you need to do is to keep your model clean and keeping only shared variables in both apps, and app specific variables in the controller, since he is the one making the link between the View and the Model.

Can I retrieve a property value from a parent model, without a DB relationship between child and parent?

I have an application serving multiple websites and would like to setup colour scheming like this:
Each element (link, text, heading, etc) has a default for the application
Each element can be overridden for individual websites
If an element is set to application default, the custom colour should be remembered for future reference
Website Configuration.cs
public class WebsiteConfiguration
{
public ApplicationConfiguration ApplicationConfiguration { get; set; }
public string CustomLinkColour { get; set; }
public bool IsCustomLinkColourActive { get; set; }
public string LinkColour
{
get
{
return (IsCustomLinkColourActive ? CustomLinkColour : ApplicationConfiguration.DefaultLinkColour);
}
}
public string CustomTextColour { get; set; }
public bool IsCustomTextColourActive { get; set; }
public string TextColour
{
get
{
return (IsCustomTextColourActive ? CustomTextColour : ApplicationConfiguration.DefaultTextColour);
}
}
// ...and so on for each colour scheme element...
}
ApplicationConfiguration.cs
public class ApplicationConfiguration
{
public List<WebsiteConfiguration> WebsiteConfigurations { get; set; }
public string DefaultLinkColour { get; set; }
public string DefaultTextColour { get; set; }
//... and so on for each colour scheme element...
}
Problems
It's a lot of work!
There are just 2 colour scheme elements in the examples above, but there may be 50+ of them.
Also, it is creating a lot of work in the view files, with if else blocks etc.
Attempted Solution
A ColourSchemeItem class manages the logic.
public class ColourSchemeItem
{
public string DefaultColour { get; set; }
public string CustomColour { get; set; }
public bool IsCustomColourActive { get; set; }
public string ActiveColour
{
get
{
return (IsCustomColourActive ? CustomColour : DefaultColour);
}
}
}
And then WebsiteConfiguration becomes much simpler...
public class WebsiteConfiguration
{
public ApplicationConfiguration ApplicationConfiguration { get; set; }
public ColourSchemeItem Link { get; set; }
public ColourSchemeItem Text { get; set; }
// ...and so on for each colour scheme element...
}
However...
But somehow I need to get the default colour from the ApplicationConfiguration into the ColourSchemeItem. And I can't figure out how.
If the ColourSchemeItem contains a reference to it's parent - WebsiteConfiguration - I get a No Key Defined for Entity error.
If ColourSchemeItem does NOT contain a reference to it's parent, I can't access the default colour from WebsiteConfiguration.ApplicationConfiguration.
The only other option I can think of it to access the DB directly from within the ColourSchemeItemclass. If there are going to be 50+ of these, I don't want to do that.
Create a custom constructor, and set the default to AplicationConfiguration

Import a VB6 structure into C#

I've been tasked with converting some legacy code to a new system and we've got some VB6 structures that are here. Is there a way to convert them into a C# structure easily?
I could redefine the structure in C# but there's no fixed strings in C#. (Or maybe I misunderstand)
Any prods in the right direction?
Private Type MapRec
Name As String * NAME_LENGTH
Revision As Long
Moral As Byte
Up As Integer
Down As Integer
Left As Integer
Right As Integer
Music As String
BootMap As Integer
BootX As Byte
BootY As Byte
Tile() As TileRec
Npc(1 To MAX_MAP_NPCS) As Integer
NpcSpawn(1 To MAX_MAP_NPCS) As SpawnRec
TileSet As Integer
Region As Byte
End Type
With respect to fixed-length strings, yikes. It ain't gonna happen because there is no equivalent construct. Unless Jon Skeet or Anders Hejlsberg know differently and can be invoked to weigh in -- I don't think even they know a way, cuz there ain't one, I am pretty certain.
On the other hand, fixed-length strings are absolutely Satanic. Which is why they didn't include them in .NET. :-)
If you were to ask me how I would convert the above MapRec object to something usable in C#, well you kind of have your choice between a struct and a class. Personally, I dislike structs. If you used a class, then you could implement a kind of bastardized fixed-string by way of your setters and getters. As seen in this example, which is how I would implement your Type MapRec:
public class MapRec
{
private const int MAX_MAP_NPCS = 25;
private int fixedLength1 = 10;
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (value.Length != fixedLength1)
{
if (value.Length < fixedLength1)
{
_name = value.PadRight(fixedLength1);
}
else
{
_name = value.Substring(0,fixedLength1);
// or alternatively throw an exception if
// a 11+ length string comes in
}
}
else
{
_name = value;
}
}
}
// Constructor
public MapRec()
{
Npc = new int[MAX_MAP_NPCS];
NpcSpawn = new SpawnRec[MAX_MAP_NPCS];
}
public long Revision { get; set; }
public byte Moral { get; set; }
public int Up { get; set; }
public int Down { get; set; }
public int Left { get; set; }
public int Right { get; set; }
public string Music { get; set; }
public int BootMap { get; set; }
public byte BootX { get; set; }
public byte BootY { get; set; }
public TileRec[] Tile { get; set; }
public int[] Npc { get; set; }
public SpawnRec[] NpcSpawn { get; set; }
public int TileSet { get; set; }
public byte Region { get; set; }
}
In the end, unless one actually needs a fixed-length string (and perhaps Microsoft.VisualBasic.VBFixedStringAttribute could do the job), I would suggest staying the heck away from them.
You may be interested in the VBFixedStringAttribute, and the VBFixedArrayAttribute although they are only utilized in a few places.
See also this question and this question.

Categories