Is there a way to make the default Enum.ToString() to convert to snake_case instead of PascalCase? And that change to be global, so I don't have to do that all over again.
public enum SpellTypes
{
HorizonFocus
}
public sealed class Settings
{
public Settings(SpellTypes types)
{
TypeString = types.ToString(); // actual: HorizonFocus, expected: horizon_focus
}
public string TypeString { get; }
}
In addition
I tried the following with Macross.Json.Extensions but it didn't apply the changes to the TypeString.
[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public enum SpellTypes
{
[EnumMember(Value = "horizon_focus")]
HorizonFocus
}
You could create an extension method for all enums.
You can cache the snake case names in a dictionary in a generic helper class, for performance.
public static string To_snake_case<T>(this T value) where T : Enum
{
return SnakeCaseHelper.Values.TryGetValue(value, out var name) ? name : null;
}
private static class SnakeCaseHelper<T> where T : Enum
{
public static Dictionary<T, string> Values = new();
static SnakeCaseHelper()
{
var names = Enum.GetNames(typeof(T));
var values = (T[])Enum.GetValues(typeof(T));
for (var i = 0; i < values.Length; i++)
Values[values[i]] = GetSnakeCase(names[1]);
}
static string GetSnakeCase(string text)
{
if(text.Length < 2)
return text;
var sb = new StringBuilder();
sb.Append(char.ToLowerInvariant(text[0]));
for(int i = 1; i < text.Length; ++i)
{
char c = text[i];
if(char.IsUpper(c))
{
sb.Append('_');
sb.Append(char.ToLowerInvariant(c));
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
}
dotnetfiddle
Snake case function is from this answer.
you can use readonly type instead of enum
public class SpellTypes
{
public static readonly SpellTypes HorizonFocus = new SpellTypes( 1, "Horizon_Focus" );
public static readonly SpellTypes HorizonFocus2 = new SpellTypes( 2, "Horizon_Focus2" );
public static readonly SpellTypes HorizonFocus3 = new SpellTypes( 3, "Horizon_Focus3" );
public readonly int num;
public readonly string name;
private SpellTypes( int num, String name )
{
this.num = num;
this.name = name;
}
}
public sealed class Settings
{
public Settings( SpellTypes types )
{
TypeString = types.name.ToString();
}
public string TypeString { get; }
}
Related
I'm trying to create a generic data exporter, where I can feed a bunch of rows and this can then get exported as excel, csv, etc...
To make it quick to specify I was planning on having the "headers" of the report specified on the same file as the rows, using static fields.
But this mess of having abstract classes with static members and the attempt of ussing them in a generic class is messy.
Is there a clean way to do this?
my attempt was having an abstract class with the base "interface" and a common method
public abstract class ReportRow
{
public static readonly string[] ColumnNames;
public static int ColumnCount => ColumnNames.Length;
public string GetColumnValueAsString(int index)
{
var value = GetColumnValue(index);
if (value is DateTime)
{
return value.ToString("dd/MM/yyyy");
}
return value.ToString();
}
}
then I have a couple of class implementations, I leave this one as an example:
public class OrdersReportRow : ReportRow
{
public new static readonly string[] ColumnNames =
{
"Date", "StoreId", "StoreName", "SkuId", "Quantity"
};
public DateTime Date { get; set; }
public int StoreId { get; set; }
public string StoreName { get; set; }
public int SkuId { get; set; }
public decimal Quantity { get; set; }
public new dynamic GetColumnValue(int index)
{
return index switch
{
0 => Date,
1 => StoreId,
2 => StoreName,
3 => SkuId,
4 => Quantity,
_ => throw new IndexOutOfRangeException(),
};
}
}
And the exporter class I wanted to be something like this:
public class ReportExporter<TReportRowType> where TReportRowType : ReportRow
{
public void Export(IEnumerable<TReportRowType> reportEntries)
{
//code to add headers
for (int i = 0; i < TReportRowType.ColumnCount; i++) // fails here because ColumnCount is not "visible"
{
AddColumn(TReportRowType.ColumnNames[i]); // also fails
}
foreach(var entry in reportEntries) {
for (int i = 0; i < TReportRowType.ColumnCount; i++) // fails here because ColumnCount is not "visible"
{
AddValue(entry.GetColumnValue(i));
CommitLine()
}
}
}
}
Those column names should be on a collection or rows level in my opinion. So that I would try something like this.
Note that the column names are automatically populated using reflection.
public abstract class ReportRow
{
public abstract dynamic GetColumnValue(int index);
public string GetColumnValueAsString(int index)
{
var value = GetColumnValue(index);
if (value is DateTime)
{
return value.ToString("dd/MM/yyyy");
}
return value.ToString();
}
}
public abstract class ReportRows<T> : IEnumerable<T> where T : ReportRow
{
public string[] ColumnNames { get => _cols.ToArray(); }
public int ColumnCount { get => _cols.Count; }
List<string> _cols;
List<T> _rows;
public ReportRows() {
_rows = new List<T>();
_cols = new List<string>();
var tt = typeof(T);
foreach(var p in tt.GetProperties()) {
_cols.Add(p.Name);
}
}
public void Add(T row) => _rows.Add(row);
public IEnumerator<T> GetEnumerator() => _rows.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class OrdersReportRow : ReportRow
{
public DateTime Date { get; set; }
public int StoreId { get; set; }
public string StoreName { get; set; }
public int SkuId { get; set; }
public decimal Quantity { get; set; }
public override dynamic GetColumnValue(int index)
{
return index switch
{
0 => Date,
1 => StoreId,
2 => StoreName,
3 => SkuId,
4 => Quantity,
_ => throw new IndexOutOfRangeException(),
};
}
}
public class OrdersReportRows : ReportRows<OrdersReportRow> { }
public class ReportExporter
{
public void Export<T>(ReportRows<T> reportEntries) where T : ReportRow
{
//code to add headers
for (int i = 0; i < reportEntries.ColumnCount; i++) // fails here because ColumnCount is not "visible"
{
AddColumn(reportEntries.ColumnNames[i]); // also fails
}
foreach(var entry in reportEntries) {
for (int i = 0; i < reportEntries.ColumnCount; i++) // fails here because ColumnCount is not "visible"
{
AddValue(entry.GetColumnValue(i));
CommitLine();
}
}
}
public void AddColumn(string s) {}
public void AddValue(object s) {}
public void CommitLine() {}
}
to call:
var or = new OrdersReportRows();
or.Add(new OrdersReportRow { Date = DateTime.Now });
var re = new ReportExporter();
re.Export(or);
I'd avoid using "new" for a method/property/field signature, I'd avoid the static public members (in combination with new). You can still use a static private field for implementation, but it's cleaner and easier to make the accessors for that field, i.e. the column names array and column count, non-static and abstract. At least "ColumnNames" should be abstract.
Sth like (untested):
public abstract class ReportRow
{
public abstract string[] ColumnNames { get; }
public int ColumnCount => ColumnNames.Length;
public string GetColumnValueAsString(int index)
{
//as is
}
}
public class OrdersReportRow : ReportRow
{
private static readonly string[] _columnNames =
{
"Date", "StoreId", "StoreName", "SkuId", "Quantity"
};
public override string[] ColumnNames => _columnNames;
//no other changes ...
}
public class ReportExporter<TReportRowType> where TReportRowType : ReportRow
{
public void Export(IEnumerable<TReportRowType> reportEntries)
{
var firstEntry = reportEntries.FirstOrDefault();
if (firstEntry == null) return;
for (int i = 0; i < firstEntry.ColumnCount; i++) // shouldn't fail any longer, because ColumnCount is now "visible"
{
AddColumn(firstEntry.ColumnNames[i]); // also should work
}
foreach(var entry in reportEntries) {
for (int i = 0; i < entry.ColumnCount; i++) // shouldn't fail any longer, because ColumnCount is now "visible"
{
AddValue(entry.GetColumnValue(i));
CommitLine()
}
}
}
This question already has answers here:
What's the correct alternative to static method inheritance?
(8 answers)
How to use polymorphism or inheritance in static classes?
(4 answers)
Closed 2 years ago.
I have a static class containing several subclasses for managing different constants.
Very different classes I want to implement the same properties depending only on the defined constants.
It looks like this:
public static class A
{
public static class Subclass1
{
public const int Constant1 = 0;
public const int Constant2 = 1;
public static List<int> Elements
{ get { return new List<int> { Constant1, Constant2 }} }
public static int Sum { get { return Elements.Sum(); } }
public static int NegSum { get { return -Elements.Sum(); } }
}
public static class Subclass2
{
public const int Constant3 = 3;
public const int Constant4 = 4;
public static List<int> Elements
{ get { return new List<int> { Constant3, Constant4 }} }
public static int Sum { get { return Elements.Sum(); } }
public static int NegSum { get { return -Elements.Sum(); } }
}
}
so that I can easily access them by
int a = A.Subclass1.Constant1;
List<int> b = A.Subclass1.Elements;
int c = A.Subclass1.Sum;
The code of the Properties Sum and NegSum is always the same.
You see the problem: I need to include them for every subclass again. Is there any way to reuse the code of the properties without implementing them for every single class?
What I would like to do is something like:
public abstract class Base
{
public abstract static List<int> Elements { get; }
public static int Sum { get { return Elements.Sum(); } }
public static int NegSum { get { return -Elements.Sum(); } }
}
public static class B
{
public static class Subclass1 : Base
{
const int Constant1 = 0;
const int Constant2 = 1;
public override static List<int> Elements
{ get { return new List<int> { Constant1, Constant2 }} }
}
public class Subclass2 : Base
{
const int Constant3 = 0;
const int Constant4 = 1;
public override static List<int> Elements
{ get { return new List<int> { Constant3, Constant4 }} }
}
}
Well, I know that in C# Inheritance like this doesn't work for static classes.
Is there any other smart way to implement this?
Maybe try implementing Subclass1 and Subclass2 without static keyword. Like this
public abstract class Base
{
public Base(params int[] elements)
{
this.Elements = new List<int>(elements);
}
public List<int> Elements { get; private set; }
public virtual int Sum { get { return Elements.Sum(); } }
public virtual int NegSum { get { return -Elements.Sum(); } }
}
public static class B
{
public static class Subclass1 : Base
{
const int Constant1 = 0;
const int Constant2 = 1;
public Subclass1() : base(Constant1, Constant2){}
}
public class Subclass2 : Base
{
const int Constant3 = 0;
const int Constant4 = 1;
public Subclass2() : base(Constant3, Constant4){}
}
}
Then add two static properties to class B
public static Subclass1 InstanceSubclass1 {get; private set}
public static Subclass2 InstanceSubclass2 {get; private set}
At the end add static constructor to class B
static B()
{
InstanceSubclass1 = new Subclass1 ();
InstanceSubclass2 = new Subclass2 ();
}
You can now access to your classes by using
B.InstanceSubclass1
What you are wanting will not be possible without some code duplication. C# doesn't handle inheritance with static the same way. While you can't override the static member of a super class, you can use new to hide and reimplement it. The downside to this is you lose the subtype contract that abstract provides, but if you really want your types to be "abstract" and have static members, you are pretty much SOL on that front.
public class Base
{
public static List<int> Elements { get; }
public static int Sum(List<int> Elements) => Elements.Sum();
public static int NegSum(List<int> Elements) => -Elements.Sum();
}
public static class B
{
public sealed class Subclass1 : Base
{
const int Constant1 = 1;
const int Constant2 = 2;
public static new List<int> Elements
{ get => new List<int> { Constant1, Constant2 }; }
public static new int Sum { get => Base.Sum(Elements); }
public static new int NegSum { get => Base.NegSum(Elements); }
}
public sealed class Subclass2 : Base
{
const int Constant3 = 3;
const int Constant4 = 4;
public static new List<int> Elements
{ get => new List<int> { Constant3, Constant4 }; }
public static new int Sum { get => Base.Sum(Elements); }
public static new int NegSum { get => Base.NegSum(Elements); }
}
}
An alternative is that you can use the singleton pattern to create the illusion that you are achieving what you want to achieve. As far as intellisense is concerned, this will produce the exact same effect of accessing the members like B.Subclass1.Sum. The downside being that this would also expose the _Subclass1 and _Subclass2 classes and pollute the namespace, but you will just have to decide if that is an acceptable trade-off.
public abstract class Base
{
public abstract List<int> Elements { get; }
public int Sum { get => Elements.Sum(); }
public int NegSum { get => -Elements.Sum(); }
}
public static class B
{
public static _Subclass1 Subclass1 { get; } = new _Subclass1();
public static _Subclass2 Subclass2 { get; } = new _Subclass2();
public sealed class _Subclass1 : Base
{
const int Constant1 = 1;
const int Constant2 = 2;
public override List<int> Elements
{ get => new List<int> { Constant1, Constant2 }; }
}
public sealed class _Subclass2 : Base
{
const int Constant3 = 3;
const int Constant4 = 4;
public override List<int> Elements
{ get => new List<int> { Constant3, Constant4 }; }
}
}
You could use interfaces and an extension method if you didn't want to have a base class:
public interface IElementsHost
{
List<int> Elements { get; }
}
public static class ElementsExtensions
{
public static int Sum(this IElementsHost host) => host.Elements.Sum();
public static int NegSum(this IElementsHost host) => -host.Elements.Sum();
}
public class Host : IElementsHost
{
public const int Constant1 = 2;
public const int Constant2 = 3;
public List<int> Elements { get; }
= new List<int>(new int[]{ Constant1, Constant2 });
}
// client code
var host = new Host();
var sum = host.Sum();
If you wanted related subclasses to have such capabilities, you'd have to do it with composition. It would look like:
public static class OtherStaticClass
{
public static ElementHost { get; } = new Host();
static OtherStaticClass()
{
Host.Elements.Add(/* some constant, etc. */);
}
}
// client code
var sum = OtherStaticClass.ElementHost.Sum();
I'm working on some classes in c#. They need to be serialized to XML to match an existing schema, but I want to build the validation in the code. e.g. something like the below;
public class Address {
public AddressLineType AddressLine1 {get;set;}
public AddressLineType AddressLine2 {get;set;}
public ShortAddressLineType AddressTown {get;set;}
public ShortAddressLineType AddressCounty {get;set;}
public PostCodeType PostCode {get;set;}
}
public class SimpleString {
public string Value {get;set;}
public override string ToString() {
return Value;
}
}
public class AddressLineType : SimpleString {
static readonly int maxLength = 60;
public static explicit operator AddressLineType(string v) {
if(!(v.Length < maxLength)) throw new Exception("String is to long!");
AddressLineType s = new AddressLineType();
s.Value = v;
return s;
}
}
public class ShortAddressLineType : SimpleString {
static readonly int maxLength = 30;
public static explicit operator ShortAddressLineType(string v) {
if(!(v.Length < maxLength)) throw new Exception("String is to long!");
ShortAddressLineType s = new ShortAddressLineType();
s.Value = v;
return s;
}
}
public class PostCodeType : SimpleString {
public static explicit operator PostCodeType(string v) {
Regex regex = new Regex(""); //PostCode pattern..
if(!(regex.IsMatch(v))) throw new Exception("Regex Validation Failed.");
PostCodeType s = new PostCodeType();
s.Value = v;
return s;
}
}
However, when this is serialized the result is;
<CurrentAddress>
<AddressLine1>
<Value>3 The Street</Value>
</AddressLine1>
<AddressLine2>
<Value>Foo Town</Value>
</AddressLine2>
</CurrentAddress>
Is it possible to collapse the special classes so that the result is this instead, but still be able to do validation? e.g. I need to specify that the AddressLineType serialises to it's Value only.
<CurrentAddress>
<AddressLine1>3 The Street</AddressLine1>
<AddressLine2>Foo Town</AddressLine2>
</CurrentAddress>
This code prints the result;
Address address = new Address();
address.AddressLine1 = (AddressLineType) "3 The Street";
address.AddressLine2 = (AddressLineType) "Foo Town";
XmlSerializer serializer = new XmlSerializer(typeof(Address));
serializer.Serialize(Console.Out, address);
I am currently building a namespace to handle complicated string actions. because I use the this string keyword, I must declare where the functions and properties are located as static. (the name of this class is "StringExtension") now I have another class named StringExtensionSettings and I use its boolean properties to determent what functions in the class StringExtension will be enabled. (for the user to choose what functions he wants to use and what not)
ex:
public class StringExtensionSettings
{
public bool DecryptString { get; set; } = true;
public bool EncryptString { get; set; } = true;
public bool RandomMix { get; set; } = true;
public bool AddMidSubString { get; set; } = true;
}
I don't want to warp the string in a class because it will make it complicated for the user. is there is any way to enable or disable function in a static class based on another class properties? and/or how to declare a class within a static class?
thank you in advance!
Additional resources:
the StringExtension class:
static class StringExtension
{
//this is what I'm trying to declare: gives an error
public StringExtensionSettings StringSettings = new StringExtensionSettings();
public static string AddMidSubString(this string Str, string MidSubString)
{
StringBuilder Result = new StringBuilder(Str);
Result.Insert(Result.Length / 2, MidSubString);
return Result.ToString();
}
public static string RandomMix(this string Str)
{
char[] array = Str.ToCharArray();
Random rng = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
var value = array[k];
array[k] = array[n];
array[n] = value;
}
return new string(array);
}
// and more functions...
Follow-up of my comment in the OP
Within a Singleton (class), you are still able/ allowed to define fields.
The singleton design pattern is an interface. It is a popular class
type for programs. It allows a class to enforce that it is only
allocated (read -> created) once.
public sealed class StringExtensionSettings
{
private StringExtensionSettings()
{
}
private static StringExtensionSettings instance = null;
public static StringExtensionSettings Instance
{
get
{
if (instance == null)
{
instance = new StringExtensionSettings();
}
return instance;
}
}
public bool DecryptString { get; set; } = true;
public bool EncryptString { get; set; } = true;
public bool RandomMix { get; set; } = true;
public bool AddMidSubString { get; set; } = true;
}
Usage:
Single Field call
StringExtensionSettings.Instance.AddMidSubString
Implementation
public static string AddMidSubString(this string Str, string MidSubString)
{
if (StringExtensionSettings.Instance.AddMidSubString)
{
StringBuilder Result = new StringBuilder(Str);
Result.Insert(Result.Length / 2, MidSubString);
return Result.ToString();
}
throw new Exception($"Not allowed to call {nameof(AddMidSubString)}");
}
Summarized; calling StringExtensionSettings.Instancecreates a new instance of StringExtensionSettings, only (once!), when the private field instance of StringExtensionSettings is null.
I have multiple type of Component class and 1 generator class. Component class has a name field and it must be unique when generated by the generator class.
So, I write the component class and generator class as below:
public class Component_A{
static int iCount;
public string name {get;set;}
public Component_A(){
name = String.Format("ComponentA_{0}", iCount++);
}
}
public class Component_B{
static int iCount;
public string name {get;set;}
public Component_A(){
name = String.Format("ComponentB_{0}", iCount++);
}
}
public class Generator(){
public List<String> generateComponent(){
Component_A a1 = new Component_A();
Component_A a2 = new Component_A();
Component_B b1 = new Component_B();
List<string> strList = new List<string>();
strList.Add(a1.name);
strList.Add(a2.name);
strList.Add(b1.name);
return strList;
}
}
public class MainClass(){
public static void main(){
Generator gen;
for(int i=0; i<2; i++){
gen = new Generator();
List<String> componentNameList = gen.generateComponent();
foreach(var s in componentNameList){
Console.Out.WriteLine(s);
}
Console.Out.WriteLine();
}
}
}
However, i want to reset the component iCount field when the new generator is initialized.
For example: the above code execution result is:
ComponentA_0
ComponentA_1
ComponentB_0
ComponentA_2
ComponentA_3
ComponentB_1
But I want it to be like this:
ComponentA_0
ComponentA_1
ComponentB_0
ComponentA_0
ComponentA_1
ComponentB_0
How can I able to achieve this?
public class Component_A{
public static int iCount;
public string name {get;set;}
public Component_A(){
name = String.Format("ComponentA_{0}", iCount++);
}
}
public class Component_B{
public static int iCount;
public string name {get;set;}
public Component_A(){
name = String.Format("ComponentB_{0}", iCount++);
}
}
public class Generator(){
public List<String> generateComponent(){
Component_A a1 = new Component_A();
Component_A a2 = new Component_A();
Component_B b1 = new Component_B();
List<string> strList = new List<string>();
strList.Add(a1.name);
strList.Add(a2.name);
strList.Add(b1.name);
return strList;
}
public void reset() {
Component_A.iCount = 0;
Component_B.iCount = 0;
}
}
Just changed iCount to public and added a reset method to change the iCounts to 0.
Use it like this:
public class MainClass(){
public static void main(){
Generator gen;
for(int i=0; i<2; i++){
gen = new Generator();
List<String> componentNameList = gen.generateComponent();
foreach(var s in componentNameList){
Console.Out.WriteLine(s);
}
gen.reset();
Console.Out.WriteLine();
}
}
}
EDIT: Since you have 100s of components, reflection seems to be a nice choice. I've moved the components in their own class.
public class Components{
public class Component_A{
public static int iCount;
public string name {get;set;}
public Component_A(){
name = String.Format("ComponentA_{0}", iCount++);
}
}
public class Component_B{
public static int iCount;
public string name {get;set;}
public Component_B(){
name = String.Format("ComponentB_{0}", iCount++);
}
}
}
public class Generator {
public List<String> generateComponent(){
var a1 = new Components.Component_A();
var a2 = new Components.Component_A();
var b1 = new Components.Component_B();
List<string> strList = new List<string>();
strList.Add(a1.name);
strList.Add(a2.name);
strList.Add(b1.name);
return strList;
}
public void reset() {
var components = typeof(Components).GetNestedTypes().ToList();
foreach (var component in components) {
var property = component.GetField("iCount", BindingFlags.Public | BindingFlags.Static);
property.SetValue(null, 0);
}
}
}
Rather than having components responsible for naming themselves, I'd create a NameGenerator class that is given a root and (optionally) starting number, that exposes NextName:
public class NameGenerator {
private int _next;
private readonly string _nameRoot;
public NameGenerator(string nameRoot) : this (nameRoot, 0)
{}
public Namegenerator(string nameRoot, int firstNumber)
{
_next = firstNumber;
_nameRoot = nameRoot;
}
public string NextName()
{
return String.Format("{0}_{1}", _nameRoot,_next++);
}
}
Your Generator class should now own a set of these objects (up to you whether to initialize these eagerly or lazily), and your Component class's should have a constructor accepting the names that the NameGenerator is spitting out.
public class Component_A{
public string name {get;private set;}
public Component_A(string name){
this.name = name;
}
}
It seems you're willing to count the A or B components generated by each instance of generator instead of just counting the total number of components A or B.
So you should put the counters in the generator instance :
public class Component_A{
public string name {get;set;}
public Component_A(int count){
name = String.Format("ComponentA_{0}", count);
}
}
public class Component_B{
public string name {get;set;}
public Component_B(int count){
name = String.Format("ComponentB_{0}", count);
}
}
public class Generator{
private int iCountA=0;
private int iCountB=0;
private Component_A createComponentA()
{
return new Component_A(iCountA++);
}
private Component_B createComponentB()
{
return new Component_B(iCountB++);
}
public List<String> generateComponent(){
Component_A a1 = createComponentA();
Component_A a2 = createComponentA();
Component_B b1 = createComponentB();
List<string> strList = new List<string>();
strList.Add(a1.name);
strList.Add(a2.name);
strList.Add(b1.name);
return strList;
}
}
Here's the output (main code remains unchanged) :
ComponentA_0
ComponentA_1
ComponentB_0
ComponentA_0
ComponentA_1
ComponentB_0