I have no idea if this is possible but it feels like it should be from using C# up to this point.
I want to have a bunch of static classes that contain 'set values' for users of the library to send into another class as parameter.
So this is where I was headed but I can't figure it out. This below is just an example of what I was thinking so don't try and work out 'why' :-)
First - The Class that will be called
public class myClass
{
public bool isError { private set; get; }
public DataTable output { private set; get; }
public String filename { set; private get; }
public settingModule settings { set; private get; }
public static void execute()
{
//Call Private 'getTheData'
//set isError accordingly
//Load output
}
private static DataTable getTheData()
{
//Open and read file for 'fileName'
//Use settings.startingRow
//Use settings.fileType
//User settings.skipEmpty
//Do some stuff
return Datatable from workings
}
}
Second - The Class I want to user to pass
public static class settingMobule
{
public static class fileTypeA
{
public static int startingRow = 1;
public static String fileType = "txt";
public static bool skipEmpty = true;
}
public static class fileTypeB
{
public static int startingRow = 10;
public static String fileType = "csv";
public static bool skipEmpty = false;
}
public static class fileTypeC
{
public static int startingRow = 3;
public static String fileType = "hex";
public static bool skipEmpty = true;
}
}
Lastly the way I want to be able to call it
myClass test = new myClass();
test.filename = "c:\\temp\\test.txt;
test.settings = settingModule.fileTypeA;
test.execute();
if(test.isError == false
{
DataTable myTable = test.output;
test.dispose()
}
Thanks in advance... and yes, "your nuts there is a much better way" is a perfectly valid answer :-)
I would also LOVE to know how to add a .dispose() to my code, it's not something i have got to yet but while I am here... :-D
No, basically; but you could do this:
public sealed class SettingMobule
{
public int StartingRow {get; private set;}
public string FileType {get; private set;}
public bool SkipEmpty {get; private set;}
private SettingMobule(int startingRow, string fileType, bool skipEmpty)
{
StartingRow = startingRow;
FileType = fileType;
SkipEmpty = skipEmpty;
}
public static SettingMobule FileTypeA {get;}
= new SettingMobule(1, "txt", true);
public static SettingMobule FileTypeB {get;}
= new SettingMobule(10, "csv", false);
public static SettingMobule FileTypeC {get;}
= new SettingMobule(3, "hex", true);
}
and pass SettingMobule.FileTypeA as an instance, etc.
No. This is not possible. It is not possible because of 2 reasons:
Static classes cannot be passed around.
The receiver cannot know that these classes are supposed to contain the same set of settings and has no way to access them.
Choose another approach where there is only one non-static file type class used to create several setting objects: (C# 6.0)
public class FileType
{
public FileType(int startingRow, string extension, bool skipEmpty)
{
this.StartingRow = startingRow;
this.Extension = extension; // 'FileType': Member names cannot be the same as their
// enclosing type.
this.SkipEmpty = skipEmpty;
}
public int StartingRow { get; }
public string Extension { get; }
public bool SkipEmpty { get; }
}
The static settings class can now present several setting objects of the same type that can be passed around.
public static class SettingModule
{
public static FileType TxtFileType { get; } = new FileType(1, "txt", true);
public static FileType CsvFileType { get; } = new FileType(10, "csv", false);
public static FileType HexFileType { get; } = new FileType(3, "hex", true);
}
Now, the test class could be written as:
public class MyTestClass
{
private FileType fileType;
private string filename;
public MyTestClass(FileType fileType, string filename)
{
this.fileType = fileType;
this.filename = filename;
}
public void Execute()
{
Console.WriteLine(
$"Extension = {fileType.Extension}, starting row = {fileType.StartingRow}");
}
}
And you can perform the test like this
var test = new MyTestClass(SettingModule.TxtFileType, #"c:\temp\test.txt");
test.Execute();
Non-static classes are a kind of template from which numerous objects can be created. Unlike static classes, such classes are types that can be used to declare variables, method parameters, properties and more.
Unfortunately in C# static classes are extremely limited in what they will allow you to do.
However, with Reflection and Types, you can do something similar, but I don't think you should.
void Main() {
var test = new MyClass(typeof(settingModule.fileTypeB));
Console.WriteLine(test.StartingRow);
}
public class MyClass {
Type SettingsClass { get; set; }
public MyClass(Type sc) {
SettingsClass = sc;
}
public int StartingRow {
get {
return (int)SettingsClass.GetField("startingRow", BindingFlags.Static | BindingFlags.Public).GetValue(null);
}
}
}
public static class settingModule {
public static class fileTypeA {
public static int startingRow = 1;
public static String fileType = "txt";
public static bool skipEmpty = true;
}
public static class fileTypeB {
public static int startingRow = 10;
public static String fileType = "csv";
public static bool skipEmpty = false;
}
public static class fileTypeC {
public static int startingRow = 3;
public static String fileType = "hex";
public static bool skipEmpty = true;
}
}
I think what you should do is create instances of a subclass and pass that:
void Main() {
var test = new MyClass();
test.Settings = settingModule.fileTypeA;
Console.WriteLine(test.Settings.startingRow);
}
public class MyClass {
public settingModule.settingsSet Settings { get; set; }
}
public static class settingModule {
public class settingsSet {
public readonly int startingRow;
public readonly string fileType;
public readonly bool skipEmpty;
public settingsSet(int sr, string ft, bool se) {
startingRow = sr;
fileType = ft;
skipEmpty = se;
}
}
public static settingsSet fileTypeA = new settingsSet(1, "txt", true);
public static settingsSet fileTypeB = new settingsSet(10, "csv", false);
public static settingsSet fileTypeC = new settingsSet(3, "hex", true);
}
You can even make it written more like your static class:
public static class settingModule {
public struct settingsSet {
public int startingRow;
public string fileType;
public bool skipEmpty;
}
public static readonly settingsSet fileTypeA = new settingsSet {
startingRow = 1,
fileType = "txt",
skipEmpty = true
};
public static readonly settingsSet fileTypeB = new settingsSet {
startingRow = 10,
fileType = "csv",
skipEmpty = false
};
public static readonly settingsSet fileTypeC = new settingsSet {
startingRow = 3,
fileType = "hex",
skipEmpty = true
};
}
Related
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();
Static class code :
static public class CommonValues
{
public static string _consumerName;
}
Assigning from a non-static class :
public class CreateSessionConsumer : IClassFixture<CommonFixture>
{
private IMockProviderService _mockProviderService;
private string _mockProviderServiceBaseUri;
public string _path = "/Security/CreateSession";
public CreateSessionConsumer(CommonFixture fixture)
{
Common.CommonValues._consumerName = "CreateSessionConsumer";
Common.CommonValues._providerName = "CreateSessionAPI";
_mockProviderService = fixture.MockProviderService;
_mockProviderService.ClearInteractions(); //NOTE: Clears any previously registered interactions before the test is run
_mockProviderServiceBaseUri = fixture.MockProviderServiceBaseUri;
CommonFixture.PactDirectory=#"..\pacts";
//CommonFixture.Provider=_provider;
}
}
Accessing in this static variable in a generic method:
public class CommonFixture : IDisposable
{
public IPactBuilder PactBuilder { get; private set; }
public IMockProviderService MockProviderService { get; private set; }
public int MockServerPort { get { return 9222; } }
public string MockProviderServiceBaseUri { get { return String.Format("http://localhost:{0}", MockServerPort); } }
public static string PactDirectory { get; set; }
public CommonFixture()
{
var pactConfig = new PactConfig
{
SpecificationVersion = "2.4.6",
PactDir = #"..\..\..\..\..\pacts",
LogDir = #".\pact_logs"
};
PactBuilder = new PactBuilder(pactConfig);
PactBuilder.ServiceConsumer(Common.CommonValues._consumerName)
.HasPactWith(Common.CommonValues._providerName);
MockProviderService = PactBuilder.MockService(MockServerPort);
}
}
Issue is, CreateSessionConsumer class is not assigning the static variable. And CommonFixture is accessing a unassigned variable.
This could not be handled the way I have asked here. Eventually had to implement Fixture class along with each class file, which sets the consumername and providername individually.
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.
There exists an enum in an assembly:
public enum TheEnumeration
{
TheFirstValue = 1,
TheSecondValue = 2
}
In another Assembly I would like to extend this enumeration with some Attributes (I know this is not valid code, just to show the idea):
public enum MyExtendedEnumeration : TheEnumeration
{
[MyAttribute("The First Value")]
TheFirstValue,
[MyAttribute("The 2nd Value")]
TheSecondValue
}
Is there a way to achieve this goal in a proper way?
You can't Extend enums, you can't inherit from them. You may just have to create a new Enum that repeats the values like a pass through and then decorate yours.
public enum MyExtendedEnumeration
{
[MyAttribute("The First Value")]
TheFirstValue = TheEnumeration.TheFirstValue,
[MyAttribute("The 2nd Value")]
TheSecondValue = TheEnumeration.TheFirstValue
}
See: Extending enums in c#
Enums cant inherit from another Enum. They are based on the System.Enum
You can put Attributes on the members.
Creating a class/Type that behaves somewhat like an Enum, may be a useful in scenarios like this.
Assumes you can "alter" the orginal enum.
///
/// Sample of a STRING or non int based enum concept.
///
public sealed class FilterOp {
private static readonly Dictionary<string, FilterOp> EnumDictionary = new Dictionary<string, FilterOp>();
private readonly string _name;
private readonly string _value;
public const string Eq = "Eq";
public const string Ne = "Ne";
public const string Gt = "Gt";
public const string Ge = "Ge";
public const string Lt = "Lt";
public const string Le = "Le";
public const string And = "And";
public const string Or = "Or";
public const string Not = "Not";
public static readonly FilterOp OpEq = new FilterOp(Eq);
public static readonly FilterOp OpNe = new FilterOp(Ne);
public static readonly FilterOp OpGt = new FilterOp(Gt);
public static readonly FilterOp OpGe = new FilterOp(Ge);
public static readonly FilterOp OpLt = new FilterOp(Lt);
public static readonly FilterOp OpLe = new FilterOp(Le);
public static readonly FilterOp OpAnd = new FilterOp(And);
public static readonly FilterOp OpOr = new FilterOp(Or);
public static readonly FilterOp OpNot = new FilterOp(Not);
private FilterOp(string name) {
// extend to cater for Name / value pair, where name and value are different
this._name = name;
this._value = name;
EnumDictionary[this._value] = this;
}
public override string ToString() {
return this._name;
}
public string Name {
get { return _name; }
}
public string Value {
get { return _value; }
}
public static explicit operator FilterOp(string str) {
FilterOp result;
if (EnumDictionary.TryGetValue(str, out result)) {
return result;
}
return null;
}
}
OutputFormatsBase is base class for managing Output Formats. OutputFormats1 and OutputFormats2 classes are inherited from OutputFormatsBase class.
I have the problem with static variable _listOfObjects which is in OutputFormatsBase class and can't find a way to solve it.
If I make _listOfObjects static everything works fine except that OutputFormats1 and OutputFormats2 classes static instances are shared, not good.
Could anyone suggest how to solve this? I completely lost.
public class OutputFormats1 : OutputFormatsBase
{
public static readonly OutputFormats1 Bmp = new OutputFormats1 { Value = "BMP", FileExtension = "bmp", Id = 1 };
public static readonly OutputFormats1 Jpg = new OutputFormats1 { Value = "JPG", FileExtension = "jpg", Id = 2 };
public static readonly OutputFormats1 Png = new OutputFormats1 { Value = "PNG", FileExtension = "png", Id = 3 };
public static readonly OutputFormats1 Tiff = new OutputFormats1 { Value = "TIFF", FileExtension = "tif", Id = 4 };
public override OutputFormatsBase Selected { get; set; }
public override OutputFormatsBase Default
{
get { return Png; }
}
}
public class OutputFormats2 : OutputFormatsBase
{
public static readonly OutputFormats2 Pdf = new OutputFormats2 { Value = "PDF", FileExtension = "pdf", Id = 1 };
public override OutputFormatsBase Selected { get; set; }
public override OutputFormatsBase Default
{
get { return Pdf; }
}
}
public abstract class OutputFormatsBase
{
private static readonly List<OutputFormatsBase> _listOfObjects = new List<OutputFormatsBase>();
public string Value { get; protected internal set; }
public string FileExtension { get; protected internal set; }
public int Id { get; protected internal set; }
public abstract OutputFormatsBase Selected { get; set; }
public abstract OutputFormatsBase Default { get; }
protected OutputFormatsBase()
{
_listOfObjects.Add(this);
}
public bool Validate(string format)
{
for (var i = 0; i < _listOfObjects.Count - 1; i++)
{
var outputFormats = _listOfObjects[i];
if (format.ToLower() == outputFormats.Value.ToLower())
{
Selected = outputFormats;
return true;
}
}
return false;
}
}
You could try something like that :
public abstract class OutputFormatsBase<T> where T : OutputFormatsBase
{
private static readonly List<T> _listOfObjects = new List<T>();
protected OutputFormatsBase()
{
_listOfObjects.Add((T)this);
}
}
You'll have one instance of _listOfObjects per template instanciation.
If you use generics then the static values will be unique to each generic type
public class OutputFormats1 : OutputFormatsBase<OutputFormats1>
{
public static readonly OutputFormats1 Bmp = new OutputFormats1 { Value = "BMP", FileExtension = "bmp", Id = 1 };
public static readonly OutputFormats1 Jpg = new OutputFormats1 { Value = "JPG", FileExtension = "jpg", Id = 2 };
public static readonly OutputFormats1 Png = new OutputFormats1 { Value = "PNG", FileExtension = "png", Id = 3 };
public static readonly OutputFormats1 Tiff = new OutputFormats1 { Value = "TIFF", FileExtension = "tif", Id = 4 };
public override OutputFormatsBase Selected { get; set; }
public override OutputFormatsBase Default
{
get { return Png; }
}
}
public class OutputFormats2 : OutputFormatsBase<OutputFormats2>
{
public static readonly OutputFormats2 Pdf = new OutputFormats2 { Value = "PDF", FileExtension = "pdf", Id = 1 };
public override OutputFormatsBase Selected { get; set; }
public override OutputFormatsBase Default
{
get { return Pdf; }
}
}
public abstract class OutputFormatsBase<T> where T:OutputFormatsBase
{
private static readonly List<T> _listOfObjects = new List<T>();
public string Value { get; protected internal set; }
public string FileExtension { get; protected internal set; }
public int Id { get; protected internal set; }
public abstract OutputFormatsBase Selected { get; set; }
public abstract OutputFormatsBase Default { get; }
protected OutputFormatsBase()
{
_listOfObjects.Add((T)this);
}
public bool Validate(string format)
{
for (var i = 0; i < _listOfObjects.Count - 1; i++)
{
var outputFormats = _listOfObjects[i];
if (format.ToLower() == outputFormats.Value.ToLower())
{
Selected = outputFormats;
return true;
}
}
return false;
}
}