EDIT: MAIN QUESTION - what will be the best way to initialize very nested object I can add anything to classes I can't change them.
In my project I have very complicated object to initialize, and in the future I will have to initialize above 100 different instances of those. I would like to ask you what will be the best way to partialy initialize them because I will never need full initialized.
public class PassivePowerUp
{
public string name = ""; //powerup name to display
public string description = ""; //description to display at runtime
public Image icon = null; //icon sprite
public Sprite defaultSprite = null; //icon sprite name on unlock
public Sprite enabledSprite = null; //icon sprite name on purchase
public Image onEnabledIcon = null; //additional sprite to show on purchase
public bool locked = false; //whether this powerup is locked (requirements)
public bool enabled = false; //whether the user bought this powerup
public float[] cost;
public PassiveTowerPowerUp towerProperties;
public PassiveEnemyPowerUp enemyProperties;
public PassivePlayerPowerUp playerProperties;
.
.
.
}
Where
public class PassivePlayerPowerUp
{
public Health health;
public Resources resources;
//Game variables
[System.Serializable]
public class Health
{
public bool enabled;
public float value;
public float interval;
public TDValue type;
}
[System.Serializable]
public class Resources
{
public bool enabled;
public float[] value;
public float interval;
public TDValue type;
public CostType costType;
}
}
The PassiveTowerPowerUp is even 3 times larger than PassivePlayerPowerUp.
Originaly those field were initialized in Unity editor so it was't a problem, but now I need to create and initialize them from code.
public PassiveTowerPowerUp towerProperties;
public PassiveEnemyPowerUp enemyProperties;
public PassivePlayerPowerUp playerProperties;
There will be only one of those initalized in instance
In C#, you do not need to initialize fields with the default values, this is done by the compiler automatically.
Any reference type (class) field will be set to null automatically.
Any value type (struct) field will be set to the default value.
For a complete reference, see MSDN: Default Values Table (C#)
So you can change for example:
public Image onEnabledIcon = null;
public bool locked = false;
to:
public Image onEnabledIcon;
public bool locked;
For setting other values, I would either hardcode them or implement a loading mechanism to get the values from e.g. an XML file which contains the names and values of the fields.
Generally you don't have to set property with default value.
Default values
For Numeric Types => (0) Or equivalent value depending on type like (0.0)
For Strings and all Reference Types => null
For bool => false
Plus You can initialize class member variables on declaration like :
public string name = "DesiredValue";
public bool locked = true;
Or you can initialize them in the constructor like:
public string name ;
public bool locked ;
public PassivePowerUp()
{
name = "DesiredValue";
locked = true;
}
Finally if the values may change from object to another then you can use parameterized constructor like
public string name ;
public bool locked ;
public PassivePowerUp(string name , bool locked)
{
this.name = name;
this.locked = locked;
}
Related
This is probably a stupid question, but just in case....
We have a 3rd party package with weird models like:
public partial class CountingDevice
{
public int countingDeviceNo { get; set; }
public string countingDeviceName { get; set; }
public string obis { get; set; }
public int integralPart { get; set; }
public bool integralPartFieldSpecified;
public int fractionalPart { get; set; }
public bool fractionalPartFieldSpecified;
public double value { get; set; }
public bool valueFieldSpecified;
public bool offPeakFlag { get; set; }
public bool offPeakFlagFieldSpecified;
public ExpectedMeterReading expectedMeterReading { get; set; }
// snipped for brevity
}
You'll notice that sometimes there are pairs of fields like integralPart and integralPartFieldSpecified.
Here is the problem: If I simply assign some value to integralPart but do not set integralPartFieldSpecified = true, the value of integralPart will be completely ignored causing the solution to fail.
So when mapping our own models to this madness, I need to litter the code with constructs like:
if (IntegralPart != null)
{
countingDevice.integralPartSpecified = true;
countingDevice.integralPart = (int)IntegralPart!;
}
Both in the interest of reducing lines of code and not stumbling over a minefield, I would like to do any one of the following:
A. Overload the = operator so it will automatically check for a property which is a boolean and has "Specified" concatenated to the current property's name. If such a property exists, it will be assigned true when the value is assigned; if not, then assignment will operate as normal. Ideally, it should be "smart" enough to assign "...Specified" to false if the value assigned is null/default/empty.
B. Create some customer operator which will do the same as A.
C. Create some method which I could invoke in a concise and preferably typesafe way to do the same.
Is this possible?
If so, how?
To make it clear: I need to build quite a few wrappers.
I don't want to repeat this logic for every field and worry about missing some fields which it applies to.
I want a generic way of assigning both fields at once if the "Specified" field exists and being able to do assignments in exactly the same way if it does not exist.
not stumbling over a minefield
Encapsulate the minefield.
If you don't control this 3rd party DTO then don't use it throughout your domain. Encapsulate or wrap the integration of this 3rd party tool within a black box that you control. Then throughout your domain use your models.
Within the integration component for this 3rd party system, simply map to/from your Domain Models and this 3rd party DTO. So this one extra line of code which sets a second field on the DTO only exists in that one place.
Another (expensive) solution would be to write a method that takes in an object, a property name, and the new property value. You can then use reflection to both set the property value for the specified property, as well as search for the bool field that you want to set (if it exists).
Note that you need to pass the correct type for the property. There's no compile-time checking that you're passing a double instead of a string for the value property, for example.
Below I've created an extension method on the object type to simplify calling the method in our main code (the method becomes a member of the object itself):
public static class Extensions
{
// Requires: using System.Reflection;
public static bool SetPropertyAndSpecified(this object obj,
string propertyName, object propertyValue)
{
// Argument validation left to user
// Check if 'obj' has specified 'propertyName'
// and set 'propertyValue' if it does
PropertyInfo prop = obj.GetType().GetProperty(propertyName,
BindingFlags.Public | BindingFlags.Instance);
if (prop != null && prop.CanWrite)
{
prop.SetValue(obj, propertyValue, null);
// Check for related "FieldSpecified" field
// and set it to 'true' if it exists
obj.GetType().GetField($"{propertyName}FieldSpecified",
BindingFlags.Public | BindingFlags.Instance)?.SetValue(obj, true);
return true;
}
return false;
}
}
After you add this class to your project, you can do something like:
static void Main(string[] args)
{
var counter = new CountingDevice();
// Note that 'valueFieldSpecified' and `integralPartFieldSpecified'
// are set to 'false' on 'counter'
// Call our method to set some properties
counter.SetPropertyAndSpecified(nameof(counter.integralPart), 42);
counter.SetPropertyAndSpecified(nameof(counter.value), 69d);
// Now 'valueFieldSpecified' and 'integralPartFieldSpecified'
// are set to 'true' on 'counter'
}
You cannot overload the = operator in C#.
You can just use custom properties and set the "FieldSpecified" fields in the setters e.g.
private int _integralPart;
public int integralPart
{
get { return _integralPart; }
set
{
_integralPart = value;
integralPartFieldSpecified = true;
}
}
public bool integralPartFieldSpecified;
Update
If you want a generic solution you can use a generic class for properties that you want to achieve the specified behaviour with e.g.
public class ValueWithSpecifiedCheck<T>
{
private T _fieldValue;
public T FieldValue
{
get
{
return _fieldValue;
}
set
{
_fieldValue = value;
FieldSpecified = true;
}
}
public bool FieldSpecified { get; set; }
}
public class Data
{
public ValueWithSpecifiedCheck<int> IntegralPart { get; set; }
}
Then the class/property would be used as following:
public static void Main()
{
var data = new Data();
data.IntegralPart = new ValueWithSpecifiedCheck<int>();
data.IntegralPart.FieldValue = 7;
Console.WriteLine(data.IntegralPart.FieldSpecified);// Prints true
}
If you implement a generic solution and add implicit conversion operators, it's quite convenient to use.
Here's a sample Optional<T> struct (I made it a readonly struct to ensure immutable mechanics):
public readonly struct Optional<T> where T : struct
{
public Optional(T value)
{
_value = value;
}
public static implicit operator T(Optional<T> opt) => opt.Value;
public static implicit operator Optional<T>(T opt) => new(opt);
public T Value => _value!.Value;
public bool Specified => _value is not null;
public override string ToString() => _value is null ? "<NONE>" : _value.ToString()!;
readonly T? _value;
}
You could use that to implement your CountingDevice class like so:
public partial class CountingDevice
{
public int countingDeviceNo { get; set; }
public string countingDeviceName { get; set; }
public string obis { get; set; }
public Optional<int> integralPart { get; set; }
public Optional<int> fractionalPart { get; set; }
public Optional<double> value { get; set; }
public Optional<bool> offPeakFlag { get; set; }
// snipped for brevity
}
Usage is quite natural because of the implicit conversions:
public static void Main()
{
var dev = new CountingDevice
{
integralPart = 10, // Can initialise with the underlying type.
value = 123.456
};
Console.WriteLine(dev.fractionalPart.Specified); // False
Console.WriteLine(dev.integralPart.Specified); // True
Console.WriteLine(dev.value); // 123.456
Console.WriteLine(dev.value.ToString()); // 123.456
Console.WriteLine(dev.fractionalPart.ToString()); // "<NONE>"
dev.fractionalPart = 42; // Can set the value using int.
Console.WriteLine(dev.fractionalPart.Specified); // True
Console.WriteLine(dev.fractionalPart); // 42
var optCopy = dev.offPeakFlag;
Console.WriteLine(optCopy.Specified); // False
dev.offPeakFlag = true;
Console.WriteLine(dev.offPeakFlag.Specified); // True
Console.WriteLine(optCopy.Specified); // Still False - not affected by the original.
Console.WriteLine(optCopy); // Throws an exception because its not specified.
}
You might also want to use optional reference types, but to do that you will need to declare a generic with the class constraint:
public readonly struct OptionalRef<T> where T : class
{
public OptionalRef(T value)
{
_value = value;
}
public static implicit operator T(OptionalRef<T> opt) => opt.Value;
public static implicit operator OptionalRef<T>(T opt) => new(opt);
public T Value => _value ?? throw new InvalidOperationException("Accessing an unspecified value.");
public bool Specified => _value is not null;
public override string ToString() => _value is null ? "<NONE>" : _value.ToString()!;
readonly T? _value;
}
Personally, I think that's a bit overkill. I'd just use nullable value types, int?, double? etc, but it depends on the expected usage.
C# doesn't allow overloading the = operator (unlike eg C++). However, your suggestion C should work. It's a bit of a hassle, too, since you'll have to write a bunch of methods, but you could write an extension method such as
public static class Extensions
{
public static void UpdateIntegralPart(this CountingDevice dev, double value)
{
dev.integralPart = value;
dev.integralPartSpecified = true;
}
}
Then you can call
countingDevice.UpdateIntegralPart(1234);
When using EF Core we have the ability to set the default value on the property.
public class Foo
{
public int Bar { get; set; }
}
public class FooConfiguration : IEntityTypeConfiguration<Foo>
{
public void Configure(EntityTypeBuilder<Foo> builder)
{
builder.Property(s => s.Bar).HasDefaultValue(1337);
}
}
When should we prefer using HasDefaultValue over initializing the default inside a class?
public class Foo
{
public int Bar { get; set; } = 1337;
// or inside constructor...
// public Foo { Bar = 1337; }
}
Or should we do both? But in this case, HasDefaultValue seems redundant. It seems like a choice where you can choose only 1 option.
The HasDefaultValue() method specifies
The default value of a column is the value that will be inserted if a new row is inserted but no value is specified for the column.
Initializing the property with default value in the class will make all objects initialized of the class have the specified default value if not instructed otherwise. In your case, that means even non attached objects will have the default value, while using the HasValue() method will be used when inserting the object into the database. It also means, if there already is empty values in the database when you are adding the HasDefaultValue() method, they will not be overwritten.
I don't know if I undestand right but you can use getter/setter methods for setting different default values for different properties like below,
private int _bar = 1337;
public int Bar{
get{
return _bar;
}
set{
_bar = value;
}
}
private int _secondBar = 1234;
public int SecondBar{
get{
return _secondBar;
}
set{
_secondBar = value;
}
}
This question already has answers here:
Using PropertyInfo to find out the property type
(2 answers)
Closed 4 years ago.
I'm working with a class whose instances are used to manages various booleans.
public bool walkable = true;
public bool current = false;
public bool target = false;
public bool selectable = false;
public bool visited = false;
public Tile parent = null;
public int distance = 0;
There's also this Reset utility function, that will just set all of the booleans back to 0
public void Reset ()
{
walkable = false;
...
}
Rather than writing out every attribute, I was hoping I could just have the function switch off any booleans that might belong to a given instance that this gets called on.
Poking around the internet I keep finding stuff on reflection, but as far as I have read this only works when one has a reference to the actual instance (not within the class definition), from the C# docs:
// Using GetType to obtain type information:
int i = 42;
System.Type type = i.GetType();
System.Console.WriteLine(type);
Is switching off the booleans from within the instance based on property possible? Is it a dumb thing to want to do? Perhaps I would be better off keeping track of the booleans in a Dictionary?
Rather than paying the cost of reflection, you could pay a much smaller cost by re-initializing an instance behind your facade.
public class AllThoseBooleans {
// expose values
public bool walkable => actual.walkable;
public bool current => actual.current;
public bool target => actual.target;
// real values defined here.
private class Actuals {
private bool walkable {get; set;}
private bool current {get; set;}
private bool target {get; set;}
}
private Actuals actual {get; set;} = new Actuals();
// reset all values to default by initialization
public void ResetAll() {
actual = new Actuals();
}
}
Please note: I didn't run this or test the access modifiers; you might have to tweak that but the concept holds: your class of booleans can "have a" store that can be re-initialized much much cheaper than reflection.
You can do this (Here Test is the class which has all the booleans):
Test test = new Test();
FieldInfo[] fields = typeof(Test).GetFields(); // Obtain all fields
foreach (var field in fields) // Loop through fields
{
string name = field.Name; // Get string name
object temp = field.GetValue(test); // Get value
if (temp is bool) // if it is a bool.
field.SetValue(test, false);
Console.WriteLine("name: {0} value: {1}",field.Name, field.GetValue(test));
}
Input class:
public class Test
{
public bool walkable = true;
public bool current = true;
public bool target = true;
public bool selectable = true;
public bool visited = true;
public string parent = null;
public int distance = 0;
}
Output:
name: walkable value: False
name: current value: False
name: target value: False
name: selectable value: False
name: visited value: False
name: parent value:
name: distance value: 0
I have a simple class that is intended for options of an winforms application. There should be a method that reset options to their default values. I know I can add a separate method to take care of this, but the code will be huge (If I add more options to the class) :
public SensorOptions()
{
ShowLabelMax = ShowLabelMin = ShowLabelAvr = ShowReceivedTextBox = true;
ChartMaxValue = 140;
ChartMinValue = -40;
ShowChartMinValue = ShowChartMaxValue = ShowChartAvrValue = ShowChartAvrLine = true;
LogFolder = Environment.SpecialFolder.MyDocuments.ToString();
LoggingEnabled = true;
}
public void ResetOptions()
{
this = new SensorOptions(); //can not do. 'this' is read-only
}
I mean I can copy/paste the code from constructor into ResetOptions() method. But is there any smarter ways to achieve this?
You cannot assign this because you may have references to this instance of your class in your program. If you could re-construct the object by re-assigning this, it would mean that all references to the old instance of the class become invalid.
No matter how many options you have in your class, you initialize each of them one or the other way (because you mention default value in your question - so you need to assign that default value somewhere at least once, probably in the constructor). Therefore, the solution to your problem is simple - move all initializers to the separate method and call it in the constructor, and then also call it every time you need to reset your options to their default values.
If any of your options are not assigned a default value explicitly, and use system default and you don't want to write option=default(optionType) for each option, you can use reflection to enumerate all fields/properties in that class and assign default values to them, like this:
public static object GetDefault(Type type)
{
if(type.IsValueType) return Activator.CreateInstance(type);
return null;
}
foreach(var field in this.GetType().GetFields())
field.SetValue(this, GetDefault(field.FieldType));
foreach(var prop in this.GetType().GetProperties())
prop.SetValue(this, GetDefault(prop.PropertyType));
Move all of the code from the constructor into the ResetOptions method, then in your constructor call the ResetOptions method. Your initialisiation code is only in one place then.
You have very simple architecture for your situation. In my opinion it would be better to apply a trick for this:
you have class for holding all your options (pseudo code):
class AllOptionsBackstage
{
public bool ShowLabelMax { get; set; }
public bool ShowLabelMin { get; set; }
public bool ShowLabelAvr { get; set; }
public AllOptionsBackstage()
{
// apply default values here
}
}
.....
class MyOptions
{
private AllOptionsBackstage _options;
public MyOptions()
{
Reset();
}
public bool ShowLabelMax
{
get{ return _options.ShowLabelMax; }
set{ _options.ShowLabelMax = value; }
}
public bool ShowLabelMin
{
get{return _options.ShowLabelMin;}
set{_options.ShowLabelMin=value; }
}
public bool ShowLabelAvr
{
get{ return _options.ShowLabelAvr;}
set{ _options.ShowLabelAvr = value; }
}
public void Reset()
{
_options = new AllOptionsBackstage(); // will reset all your options to default
}
}
I use the following dedicated class to manage session variables in my applications (ignore misspelled names; that's intentional):
This first code block is for usage. You can see the class it is calling on, at the next code block
//'importing' the class for current project
using SeSn = Debug_Tests.Seseions.SeSn;
// creating an object (usually with name related to currentProject)
public static SeSn.CreatCurrentSesionVariablsStructNamed CurSesVarStruct = new Seseions.SeSn.CreatCurrentSesionVariablsStructNamed();
// the long name helps me in this little 'chaos'
This is an instance of a struct, that is 'grouping' or 'tying' all my globals into one bundle. Whenever I may need to store my global variables, I will assign the values into the appropriate-struct-variable that CurSesVarStruct has to offer.
Then all I need is to access session variables once, only to extract the "Variable-collection" -object, ... as it is actually a session variable that I keep its name constant - _CurrentSesionGlobals.
In short, it's the struct that is stored in the session as one of the session variables - data type = object, or you could say a clone of the struct to be saved between sessions.
Since I have that and can use it with _CurrentSesionGlobals, I could just access any value I need from session through the following, for example:
Assign the struct before storing it in Session:
CurSesVarStruct.SelectedUercustid = custID;
Then the next method - ExtrctSesnVar() below, allows me to use for example:
Extract a variable that was saved in last session:
custID = ExtractSesnVar().SelectedUercustid;
So SelectedUercustid is actually one of the struct members.
The Question/Problem
Performing extraction of _CurrentSesionGlobals out of the session variables.
public static SeSn.CreatCurrentSesionVariablsStructNamed ExtrctSesnVar()
{
var CurrAppGlobals = SeSn.GetValueAS.ACloneOfTheStructObj("_CurrentSesionGlobals");
return (SeSn.CreatCurrentSesionVariablsStructNamed)CurrAppGlobals;
//the question is refereing this location.
}
How can I have a return value for a null result, or a condition that will first ask if the object / a given Session Variable, that I am trying to extract isn't null, or does not exist?
Currently there's an exception error while I am trying to get the value of a non-existing session variable.
The next code block is a class that I add into the solution, as a helper to every website application. It's actually a namespace, so the class that is responsible to handle session variables is Sesn:
namespace Seseions {
public class Sesn {
public static bool isNotEmpty() {
return HttpContext.Current.Session.Keys.Count > 0;
}
public struct CreatCurrentSesionVariablsStructNamed {
// some of commonly used variables- still testing options..
public int ManagerCustID;
public int SelectedUercustid;
public int recordID;
public int SelectedMonth;
public int SelectedChosenWorker;
public int SelectedYear ;
public string SelectedTable;
public string SelectedColumn;
public string SqlSelectCommandLastQuery;
public string TableOfUsersReference;
public List<string> Fontlist { get; set; }
}
// converts and extract values of session variables
public class GetValueAS {
public static CreatCurrentSesionVariablsStructNamed ACloneOfTheStructObj(string currntProjectSesVarStructName) {
if(HttpContext.Current.Session[currntProjectSesVarStructName] != null) {
return (CreatCurrentSesionVariablsStructNamed)HttpContext.Current.Session[currntProjectSesVarStructName];
}
public static int _Int(string SesParameterValToReturn) {
return Convert.ToInt32(HttpContext.Current.Session[SesParameterValToReturn]);
}
public static string _String(string SesParameterValToReturn) {
return Convert.ToString(HttpContext.Current.Session[SesParameterValToReturn]);
}
public static DataSet _DataSet(string SesParameterValToReturn) {
return (DataSet)HttpContext.Current.Session[SesParameterValToReturn];
}
public static DataTable _DataTable(string SesParameterValToReturn) {
return (DataTable)HttpContext.Current.Session[SesParameterValToReturn];
}
public static bool _Bool(string SeSnVarToCheckOn) {
if (HttpContext.Current.Session[SeSnVarToCheckOn] == null)
return false;
return (bool)HttpContext.Current.Session[SeSnVarToCheckOn];
}
}
// an easy way to access and mange session variables actions
public enum Act {
Add, Remove, Replace
}
public static void Modify(Act action, string New_SesnVarName= null, object NewP_Value=null, string Currnt_Ses_SesnVarName=null) {
switch (action) {
case Act.Remove:
if (isNotEmpty()) {
HttpContext.Current.Session.Remove(CurSes_ParamName);
}
break;
case Act.Replace:
HttpContext.Current.Session.Remove(CurSes_ParamName);
HttpContext.Current.Session.Add(New_SesnVarName, NewP_Value);
break;
case Act.Add:
HttpContext.Current.Session.Add(NewQs_SesnVarName, NewP_Value);
break;
}
}
}
}
Just don't do this.
critical: do not put Session (user) related data in static variables. It is not thread-safe.
best practice: try to avoid static in ASP.NET for everything else too.
best practice: do not use structs for anything but small, immutable and identity-less types
It seems you are over-engineering this. All you need (for now) is to use some constants for the strings:
public static class SessionKeys
{
public const string ManagerCustID = "ManagerCustID";
...
}
and then you can start focusing on code that adds value to your app.