Sorry if the question's title is confusing,but i don't know how to ask it.
what is really want is to have read-only data that will never change.
currently i have two enums MeterType and SubMeterType
public enum MeterType
{
Water = 1001,
Electricity = 1004,
Gas = 1007
}
and
public enum SubMeterType
{
DrinkingWater = 1002,
UsageWater = 1003,
SubsidiseGas = 1008,
NonSusbsidisedGas = 1009
}
Now i would like to use these as follows
To get the MeterType
string meterType = MeterType.Water.ToString("d");
and to get the SubMeterType, is it possible to have something like
string subMeterType = MeterType.Water.DrinkingWater("d");
Shall go for another approach using classes with readonly properties ?
or modify these enums to suit my requirement.
Instead of using enums you might use constant integers in nested classes:
public static class MeterType
{
public const int Water = 1001;
public const int Electricity = 1004;
public const int Gas = 1007;
public static class Waters
{
public const int DrinkingWater = 1002;
public const int UsageWater = 1003;
}
public static class Gases
{
public const int SubsidiseGas = 1008;
public const int NonSusbsidisedGas = 1009;
}
}
Just use a nested enum:
public class MeterType
{
public enum Water { }
}
But in this case you can't use MeterType.Water directly, this is not possible by default. Try use nested objects then or a secondary enum for the MeterType.
public enum MeterType { }
public enum MeterTypeWater { }
In this case you need a property with a different name for each of the enums. Best solution is to not use a nested class:
public class MeterType
{
public static WaterType Water { get; }
}
public class WaterType
{
public readonly SubWaterType DrinkingWater = SubWaterType.DrinkingWater;
}
You cannot nest enums but you already know that. What you can do is to have const or readonly properties/fields which map to the various types you want. Then in each of the types, you define fields/properties for the subtypes.
public static class MeterTypes
{
public static readonly Electricity electricity;
public static readonly Gas gas;
public static readonly Water water;
static MeterTypes()
{
// initialize the meter types to their default
MeterTypes.Water = Water.GenericWater;
MeterTypes.Gas = Gas.GenericGas;
MeterTypes.Electricity = Electricity.GenericElectricity;
}
private MeterTypes()
{
// private initialization prevents others from creating the class
}
public class Electricity
{
public enum Type
{
Generic = 1007,
SubsidisedElectricity = 1008,
NonSubsidisedElectricity = 1009
}
public static readonly Electricity GenericElectricity;
public static readonly Electricity SubsidisedElectricity;
public static readonly Electricity NonSubsidisedElectricity;
private Type ElectricityType;
static Electricity()
{
SubsidisedElectricity = new Electricity(Type.SubsidisedElectricity);
NonSubsidisedElectricity = new Electricity(Type.NonSubsidisedElectricity);
GenericElectricity = new Electricity(Type.Generic);
}
// private constructor prevents creation from outside the class
private Electricity(Type ElectricityType)
{
this.ElectricityType = ElectricityType;
}
public override string ToString()
{
return ElectricityType.ToString();
}
public string ToString(string format)
{
return ElectricityType.ToString(format);
}
}
public class Gas
{
public enum Type
{
Generic = 1007,
SubsidisedGas = 1008,
NonSubsidisedGas = 1009
}
public static readonly Gas GenericGas;
public static readonly Gas SubsidisedGas;
public static readonly Gas NonSubsidisedGas;
private Type gasType;
static Gas()
{
SubsidisedGas = new Gas(Type.SubsidisedGas);
NonSubsidisedGas = new Gas(Type.NonSubsidisedGas);
GenericGas = new Gas(Type.Generic);
}
// private constructor prevents creation from outside the class
private Gas(Type gasType)
{
this.gasType = gasType;
}
public override string ToString()
{
return gasType.ToString();
}
public string ToString(string format)
{
return gasType.ToString(format);
}
}
public class Water
{
public enum Type
{
Generic = 1001,
DrinkingWater = 1002,
UsageWater = 1003
}
public static readonly Water GenericWater;
public static readonly Water DrinkingWater;
public static readonly Water UsageWater;
private Type waterType;
static Water()
{
DrinkingWater = new Water(Type.DrinkingWater);
UsageWater = new Water(Type.UsageWater);
GenericWater = new Water(Type.Generic);
}
// private constructor prevents creation from outside the class
private Water(Type waterType)
{
this.waterType = waterType;
}
public override string ToString()
{
return waterType.ToString();
}
public string ToString(string format)
{
return waterType.ToString(format);
}
}
}
This can be used as such
var w = MeterTypes.water; // will give generic water
var uw = MeterTypes.Water.UsageWater // will give usage water
and you get the added use of the Enum.ToString() methods too.
You'll have to note that this implementation relies on C#'s case sensitivity. This makes MeterTypes.electricity and MeterTypes.Electricity refer to a field and a class respectively. This code will is very likely to fail if it ever gets used in a language that is not case sensitive (e.g. VB.NET). You could circumvent this by using a different name for the static fields in the MeterTypes class (e.g. _Electricity instead of electricity).
Related
I was trying to emulate an enum in C# i can use with string values by using a class with static only members like here:
internal class TruckSizeType
{
private static string? Value;
private TruckSizeType(string value) { Value = value; }
public static TruckSizeType SMALL { get { return new TruckSizeType("small"); }}
public static TruckSizeType MEDIUM { get { return new TruckSizeType("medium"); }}
public static TruckSizeType BIG { get { return new TruckSizeType("big"); }}
public static TruckSizeType GIANT { get { return new TruckSizeType("giant"); }}
public static List<TruckSizeType> ALL = new ()
{
SMALL,
MEDIUM,
BIG,
GIANT
};
public override string ToString()
{
return Value ?? "";
}
}
For some reason, the list member "ALL" shows up as filled with 4 members (which is correct) during runtime but all of those are of the type GIANT. I cannot figure out why all the members are of type GIANT in the ALL list when i initialized them with all of the 4 different types instead. Does anybody understand this? I am not a c# programmer but have quite a bit of experience in OOP languages. Perhaps it is a case of missing the obvious. Here is a screenshot from the debugger showing the value of the list after assignment:
I think you need to use static fields instead of properties so you don't create new instances each time you reference them, and you need to have an actual class with a private value to hold the string:
internal class TruckSizeType {
private readonly string Value;
private TruckSizeType(string value) => Value = value;
public static readonly TruckSizeType SMALL = new TruckSizeType("small");
public static readonly TruckSizeType MEDIUM = new TruckSizeType("medium");
public static readonly TruckSizeType BIG = new TruckSizeType("big");
public static readonly TruckSizeType GIANT = new TruckSizeType("giant");
public static readonly ReadOnlyCollection<TruckSizeType> ALL = new List<TruckSizeType>() { SMALL, MEDIUM, BIG, GIANT }.AsReadOnly();
public override string ToString() => Value ?? "";
}
What I'm looking for is a way to create a class (NotDefinedClass) with a simple bool variable and a "class variable" that I can declare in the constructor. The classes that I will declare in the constructor will have their own methods. And later I want to access theses methods like "ClassOne.CLASS1.MethodOne();"
public class NotDefinedClass
{
public bool Active;
public NotDefinedYetClass;
public NotDefinedClass(class _Class, bool _Active){
NotDefinedYetClass = _Class;
Active = _Active;
}
}
public NotDefinedClass ClassOne = new NotDefinedClass(CLASS1, false);
public NotDefinedClass ClassTwo = new NotDefinedClass(CLASS2, false);
public NotDefinedClass ClassThree = new NotDefinedClass(CLASS3, false);
Problem
A class is a type: we can't "assign a class to variable" in C#.
We can create an object instance being of type a class, or struct, and assign it to a variable:
var instanceOfMyClass = new MyClass();
Also we can get an instance of a Type class instance that describes the targetted class and assign it to a variable like:
var myClassType = instanceOfMyClass.GetType();
var myClassType = typeof(MyClass);
But what to do with that?
public Type NotDefinedYetClass;
And it is impossible to write this and replace T at runtime with something without using generics:
public T NotDefinedYetClass;
Also, it is impossible to use the keyword class as a type of a variable or method parameter:
public NotDefinedClass(class _Class, bool _Active)
Solution
A dynamic object can be used... or not: more information on goals and design may be needed.
public class NotDefinedClass
{
public bool Active;
public dynamic NotDefinedYetClass;
public NotDefinedClass(dynamic _Class, bool _Active)
{
NotDefinedYetClass = _Class;
Active = _Active;
}
}
Personally, I prefer generics to dynamics, except in a few cases where they are more powerfull and simpler.
We can create a generic version of the class to solve the problem using for example a T artifact as a generic type parameter that allows to create as many types as needed:
public class EmbededInstance<T> where T : class
{
public bool Active { get; /* private */ /* set; */ }
public T Instance { get; /* private */ /* set; */ }
public EmbededInstance(T instance, bool active)
{
Instance = instance;
Active = active;
}
}
Usage
public EmbededInstance<MyClass1> Embeded1
= new EmbededInstance<MyClass1>(new MyClass1(), false);
public EmbededInstance<MyClass2> Embeded2
= new EmbededInstance<MyClass2>(new MyClass2(), false);
public EmbededInstance<MyClass3> Embeded3
= new EmbededInstance<MyClass3>(new MyClass3(), false);
Having for example:
public class MyClass1
{
public void MyMethod() { }
}
public class MyClass2
{
public int MyInteger { get; set; }
}
public class MyClass3
{
}
To use the embeded instance members, properties and methods:
Embeded1.Instance.MyMethod();
Embeded2.Instance.MyInteger = 10;
More information
C# MSDoc
Generics in .NET
Generic classes and methods
Generics Level 1
Generics level 2
Just use Type for this:
public class NotDefinedClass
{
public bool Active;
public Type NotDefinedYetClass;
public NotDefinedClass(Type _Class, bool _Active){
NotDefinedYetClass = _Class;
Active = _Active;
}
}
I am having problems understanding how to correctly encapsulate my class. It is (or should be) an inmutable class.
I am using a "helper class" and I want it to be not accesible from the outside.
namespace MyApp
{
[Flags]
public enum OctaveGroups
{
None = 0,
oneOctave = 1
}
class Frequencies
{
// HelperClass
public class Frequency
{
public string Name { get; set; }
public OctaveGroups Octave { get; set; }
}
public readonly static List<Frequency> All = new List<Frequency>
{
#region Complete Frequencies Data
new Frequency { Name = "63", Hz = 63,
Octave = OctaveGroups.oneOctave | OctaveGroups.None,
},
new Frequency { Name = "80", Hz = 80,
Octave = OctaveGroups.None,
}
// And so on..
//..
#endregion
};
public readonly List<Frequency> OneOctave = All.Where(f => f.Octave.HasFlag(OctaveGroups.oneOctave)).ToList();
public readonly List<Frequency> None = All.Where(f => f.Octave.HasFlag(OctaveGroups.None)).ToList();
}
}
If I make my Frequency class protected or private I get this error:
Inconsistent accessibility: field type 'List'
is less accesible than field 'Frequencies.All'
I get the same error if I make class Frequency and List<Frequency> Allprotected and try to make a method that returns a List<Frequency> like:
public List<Frequency> GetAll()
{
return All.Where(f => f.Octave.HasFlag(OctaveGroups.OneOctave)).ToList();
}
How will be the correct way to expose just .All .OneOctave and .None fields while keeping them read only?
You can't expect to hide Frequency when you are planning in having public methods returning List<Frequency>.
Now, what I understand is your issue is that you need accessible property setters in Frequency from Frequencies but you don't want to expose them to the outside. The way to do this is through an interface that only exposes getters:
public interface IFrequency
{
string Name { get; }
OctaveGroups Octave { get; }
}
And now, you make Frequencies.Frequency a private nested class and you expose only IFrequency:
class Frequencies
{
// HelperClass
private class Frequency: IFrequency
{
public string Name { get; set; }
public OctaveGroups Octave { get; set; }
}
public readonly static List<IFrequency> All = new List<IFrequency>
{
#region Complete Frequencies Data
new Frequency { Name = "63", Hz = 63,
Octave = OctaveGroups.oneOctave | OctaveGroups.None,
},
new Frequency { Name = "80", Hz = 80,
Octave = OctaveGroups.None,
}
// And so on..
//..
#endregion
};
public readonly List<IFrequency> OneOctave = All.Where(f => f.Octave.HasFlag(OctaveGroups.oneOctave)).ToList();
public readonly List<IFrequency> None = All.Where(f => f.Octave.HasFlag(OctaveGroups.None)).ToList();
}
Now a consumer of Frequencies will only see IFrequency instances where no setter is exposed and is therefore immutable to the outside world (excluding reflection of course).
The correct way is not to hide them.
You simply cannot both hide and expose a class to the outside world, at the same time.
So if you want to declare a public method returning the object, or a collection of the object, you must make the type of the object in question public as well.
Try adding an internal constructor to your Frequency class. This will allow you to construct a Frequency from within the class but disallow outside classes from constructing it. Since it can't be constructed on the outside no one outside of the class will be able to add a new one to your Lists since they are typed to Frequency.
Example:
public class ExternalType
{
public class InternalType
{
internal InternalType(string someString)
{
SomeStringProp = someString;
}
public string SomeStringProp { get; private set; }
}
public readonly List<InternalType> InternalTypes = new List<InternalType>()
{
new InternalType("test")
};
}
If you try to instantiate InternalType outside of ExternalType you will get a compiler error. However your dependents will be able to read the list.
I'm experimenting with an API for publishing values at a given time (tuples of value and time). These samples will be used by a data viewer (e.g. a graph).
I want to associate the value with a Quantity and a Unit, for example length in meters. That way my "viewer" can scale it appropriately.
I'm looking for a sort of hierarchical enum, like this:
enum Quantity
{
Mass.Kg,
Mass.g,
Length.m,
Length.mm
}
But this doesn't exist in C#.
I'm not sure the best pattern to express this and I've come up with the following. Is there a recognised, or better way to do this?
using System;
using Moq;
namespace ConsoleApplication26
{
class Program
{
static void Main(string[] args)
{
//use a Mock to play with the API
Mock<ITelemetryPublisherFactory> mockTelemetryPublisherFactory = new Mock<ITelemetryPublisherFactory>();
var telemetryPublisherFactory = mockTelemetryPublisherFactory.Object;
//example usages
var massTelemetryPublisher = telemetryPublisherFactory.GetChannelSamplePublisher<Double>("My Mass", Mass.Kg);
massTelemetryPublisher.PublishChannelSampleAtTimeNow(83.4);
var lengthTelemetryPublisher = telemetryPublisherFactory.GetChannelSamplePublisher<Int32>("My Height", Length.μm);
lengthTelemetryPublisher.PublishChannelSampleAtTimeNow(1800000);
//10 years time..
lengthTelemetryPublisher.PublishChannelSampleAtTimeNow(1800000);
massTelemetryPublisher.PublishChannelSampleAtTimeNow(120.1);
}
}
public interface ITelemetryPublisherFactory
{
ITelemetryPublisher<T> GetChannelSamplePublisher<T>(String channelName, Quantity quantity);
}
public interface ITelemetryPublisher<T>
{
void PublishChannelSampleAtTimeNow(T sampleValue);
}
public abstract class Quantity {}
public class Mass : Quantity
{
private enum Unit
{
g,
Kg
}
private readonly Unit _unit;
private Mass(Unit unit)
{
_unit = unit;
}
public static Quantity Kg {get { return new Mass(Unit.Kg); }}
public static Quantity g { get { return new Mass(Unit.g); } }
public override string ToString()
{
return String.Format("Mass.{0}", _unit);
}
}
public class Length : Quantity
{
private enum Unit
{
m,
mm,
μm,
beardSecond
}
private readonly Unit _unit;
private Length(Unit unit)
{
_unit = unit;
}
public static Quantity m { get { return new Length(Unit.m); } }
public static Quantity mm { get { return new Length(Unit.mm); } }
public static Quantity μm { get { return new Length(Unit.μm); } }
public static Quantity beardSecond { get { return new Length(Unit.beardSecond); } }
public override string ToString()
{
return String.Format("Length.{0}", _unit);
}
}
}
I think it's better to create a Unit class for the unit of measure and a Quantity class that associates a unit of measure with an amount. Look at the Quantity pattern for the idea. Since you also want to record the "type" of the unit of measure, you could create a UnitType class that records that information:
public sealed partial class UnitType {
public string Name { get; private set; }
public UnitType(string name) {
Name = name;
}
}
public sealed partial class Unit {
public string Name { get; private set; }
public UnitType Type { get; private set; }
public Unit(string name, UnitType type) {
Name = name;
Type = type;
}
}
(You should make them proper value types by overriding Equals and GetHashCode)
The Unit class can be extended to provide for e.g. conversions, compound units, formatting and parsing.
Then, you can define the common cases inside the classes:
public partial class UnitType {
public static readonly UnitType Mass = new UnitType("Mass");
public static readonly UnitType Length = new UnitType("Length");
}
public partial class Unit {
public static readonly Unit Grams = new Unit("g", UnitType.Mass);
public static readonly Unit Kilos = new Unit("kg", UnitType.Mass);
// ...
}
Or define your "hierarchies" with static classes:
public static class Mass {
public static readonly UnitType Type = new UnitType("Mass");
public static readonly Unit Grams = new Unit("g", Type);
public static readonly Unit Kilos = new Unit("kg", Type);
...
}
public static class Length ...
The Quantity class would also be an immutable value type (just showing its usage):
var eniacWeight = new Quantity(27, Mass.Tons);
Or you could use extension methods to create Quantitys:
var eniacWeight = 27.Tons();
(from ENIAC)
This is not possible. Enums are primitive types and cannot inherit from other enums, as inheritance is a property of objects.
Hierarchical enum isn't possible, as noted above. If you're exclusively using metric, though, you can utilise standard prefixes if it helps.
enum MeasurementUnits
{
Gram,
Metre,
Litre,
Hectare
// etc
}
enum MeasurementPrefix
{
Milli,
Natural,
Kilo,
Mega
// etc
}
This may not be precisely what you want, but it will provide the type of 'grouping' that you might be looking for (e.g. group measurements that are about length, weight etc by checking their 'units' value).
Your suggested approach seems reasonable to me, and I use something similar in a project of mine. However, I keep the actual value part of the object, and I use struct instead of class, since they are naturally value types. Inheritance is not necessary here (and not possible with structs, anyways), so I use an interface to create a contract and act as a constraint when needed (I called it IUnitOfMeasure).
I do not recommend creating one enum with all the units of the various types of measurement combined; it is hell validating the unit to make sure someone didn't reference a Mass unit when working with Length.
public interface IUnitOfMeasure<TThis>
where TThis : IUnitOfMeasure<TThis>
{
TThis ConvertTo(TThis value);
}
public struct Mass : IUnitOfMeasure<Mass>
{
public enum Units
{
Gram,
Kilogram
}
private double _value;
private Mass.Units _unit;
public double Value { get { return _value; } }
public Mass.Units Unit { get { return _unit; } }
public Mass(double value, Mass.Units unit)
{
_value = value;
_unit = unit;
}
public Mass ConvertTo(Mass value)
{
switch(value.Unit)
{
case Units.Gram:
return new Mass(Unit == Units.Gram ? Value : Value/1000, Units.Gram);
case Units.Kilogram:
return new Mass(Unit == Units.Gram ? Value*1000 : Value, Units.Kilogram);
default:
throw new NotImplementedException();
}
}
public override string ToString()
{
return string.Format("{0} {1}", Value, Unit);
}
public static readonly Mass G = new Mass(0, Units.Gram);
public static readonly Mass Kg = new Mass(0, Units.Kilogram);
}
Usage:
var kg = new Mass(5.0, Mass.Units.Kilogram);
Console.WriteLine(kg); // writes "5 Kilogram"
var g = kg.ConvertTo(Mass.G);
Console.WriteLine(g); // writes ".005 Gram"
If you don't care about keeping the value, and just want to keep enum/static values in a central place:
public static class UnitOfMeasure
{
public enum Mass
{
Gram,
Kilogram
}
public enum Length
{
Meter,
Kilometer
}
// etc.
}
Usage: var unit = UnitOfMeasure.Mass.Kilogram;
You cannot introduce inheritance with enums. Enums are just a convenience mechanism to allow you to use meaningful textual identifiers in your code. From The code you have, I suggest you either use an enum like;
public enum UnitOfMeasure
{
MassGrams,
MassKg,
LengthMM,
LengthCM,
. . .
}
Or split it out to where it's appropriate, so that Mass and Length are defined separately for example.
The 'inheritance' is just something you've introduced in your thinking about this problem, but it isn't necessary to your solution. When you want to deal with Mass, you only look at the flags/enums appropriate to mass.
public class BlockType
{
public static BlockType Dirt_Block = new Block("Blah! values here");
}
public struct Block
{
public static string Value;
public Block(string value)
{
value = value;
}
}
Is there any way I can get the value from DirtBlock? BlockType.Dirt_Block.Value Dosent work, Im not sure if this is possible, if not any ways to get the same result? (Theres more values, but I shortened it for size) Btw, Im accessing BlockType.Dirt.value from anouther class. I only want to get one value out of it though
That's because Dirt_Block is a BlockType, not a Block. In fact, I wouldn't expect this code to compile, as there is no way of converting a Block to a BlockType.
I'm not quite sure what you're after, but it sounds like you have a collection of block types that would suit an enumeration:
public enum BlockType
{
Dirt,
Wood,
Metal
}
and you have a collection of Blocks that each have a block type:
public class Block
{
public BlockType Type { get; set; }
}
Here, we are using a public auto property. You should avoid using public fields (no getters or setters).
Now, to create a new Block, you can use object initialisation:
var block = new Block { Type = BlockType.Metal };
Alternatively, you could create a Block constructor which takes a BlockType parameter.
Other way to achieve it.
I think this approah provides an easier way to load/save tilemaps, and let defining block properties from text if needed.
Strict OOP with virtual methods and intensive inheritance is not a good idea for a game that may need optimizations to run fine.
Of course it can be improved or done in other way. ;)
public struct BlockProperty
{
public Texture2D Texture;
public string Name;
}
public class BlockProperties
{
static readonly List<BlockProperty> Blocks;
public static readonly BlockProperty Dirt;
public static readonly BlockProperty Grass;
public static readonly BlockProperty Wall;
static BlockProperties( )
{
ContentManager Content = Game1.Instance.Content;
Blocks = new List<BlockProperty>( )
{
(Dirt = new BlockProperty( ) { Name = "Dirt", Texture = Content.Load<Texture2D>( "textures/dirt" ) }),
(Grass = new BlockProperty( ) { Name = "Grass", Texture = Content.Load<Texture2D>( "textures/grass" ) }),
(Wall = new BlockProperty( ) { Name = "Wall", Texture = Content.Load<Texture2D>( "textures/wall" ) }),
};
}
public static BlockProperty ByName( string name )
{
return Blocks.FirstOrDefault( b => b.Name == name );
}
}
public class Block
{
public BlockProperty BlockType;
pulic Vector2 Position;
public Block( BlockProperty block )
{
this.BlockType = block;
}
public Block( string block )
{
this.BlockType = BlockProperties.ByName(block);
}
}
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
public static Game1 Instance { get; private set; }
Block Block;
public Game1( )
{
Instance = this;
graphics = new GraphicsDeviceManager( this );
}
protected override void LoadContent( )
{
Block = new Block("Dirt") { Position = new Vector2(100,100) };
}
}
Assuming you mean Dirt_Block to be of type Block - your Block Value field is static - that means it is associated with the Block type, not any particular instance. Make it a public field (or property) and your access will work:
public class BlockType
{
public static Block Dirt_Block = new Block("Blah! values here");
}
public struct Block
{
public string Value;
public Block(string value)
{
value = value;
}
}
Also if there is no particular reason you are going with a struct here, I would suggest making Block a class and expose Value as a public property.
Your doubt isn't very clear... but I think what you want is something like this... using OOP paradigm on the block classes.
public class BlockType
{
public virtual string Value;
public static BlockType Dirt = new Block("Blah! values here");
}
public class Block : BlockType
{
private string value;
public Block(string value)
{
this.value = value;
}
public string Value
{
get { return value; }
}
}
Right?