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
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);
I use Mapster package for mapping two objects.
An existing object is updated (patched) by applying some rules in the source object and ignore some properties based on their values and Property Type using a function.
I try to use the method IgnoreMember((member, side) to ignore members.
The function return false when ignoring member, like the code below:
//sourceValue: the value of the property (member) in the object
//Return: true: map members, false: ignore members
bool validMembers(object sourceValue)
{
if (sourceValue is null) return false;
switch (sourceValue)
{
//ignore string null or empty
case string { Length: > 0 }:
return true;
//ignore empty collection
case ICollection { Count: > 0 } l:
return true;
case bool b:
return b;
case int i:
return i != 0;
//.....
// other rules
default:
return false;
}
}
Mapster is configured as in the next code:
static void Test1()
{
//the object that is required to be updated:
var destination = new Foo{Name = "bar"}; //actually it's created from json string.
//the source object used to update destination object.
var source = new Foo{Name="", Address="city", Kind = Kind.Male, Cert = new List<string>() {"c1", "c2"}};
//****** Configuration********************
//global setting
//THIS LINE NEED TO BE CORRECTED
TypeAdapterConfig.GlobalSettings.Default
.IgnoreMember((member, side) => !validMembers(what_member_property????)); //What the parameter that should be passed and have the value of member !!!
TypeAdapterConfig<Foo, Foo>.NewConfig().IgnoreNullValues(true);
//Mapping to an existing object
source.Adapt(destination);
}
}
class Foo
{
public string Name { get; set; }
public string Address { get; set; }
public Kind Kind { get; set; }
public IEnumerable<string> Cert { get; set; }
}
enum Kind
{
UnDefined,
Male,
Female
}
In the method IgnoreMember((member, side) => !validMembers(member)) , I don't find an api in the documentation that is represent the value of the member to be passed to the my ValidMembers function.
The Question:
What the member parameter that should be passed to the function ValidMembers?
Is there any other way to apply these rules (not member to member mapping)?
I have provided dotnetfiddle to show the issue.
I have an enum that holds feature names such as
public enum FeatureNames{
[Description("Amazing Feature")]
AmazingFeature,
[Description("Amazing New Feature")]
AmazingNewFeature
}
I have a domain entity that has properties representing each of the feature which indicates if the feature is turned on or off
public class CompanyAccount{
public bool IsAmazingFeatureEnabled{get;set;}
public bool IsAmazingNewFeatureEnabled{get;set;}
}
This is how the existing application was written and hence I don't want to make drastic changes to DB at this point. So now I am trying to write a genric method that will take in a string or enum value indicating feature and check if the property matching the same feature is enabled or not(true or false).
public bool IsEnabled(FeatureNames featureName){
if(featureName is FeatureNames.AmazingFeature){
return companyAccount.IsAmazingFeatureEnabled;
}
else if(featureName is FeatureNames.AmazingNewFeature){
return companyAccount.IsAmazingNewFeatureEnabled;
}
Is there a better way to handle this? Can we avoid the if condition?
You could use a switch expression (C# 8.0)
public bool IsEnabled(FeatureNames featureName) =>
featureName switch {
FeatureNames.AmazingFeature => companyAccount.IsAmazingFeatureEnabled,
FeatureNames.AmazingNewFeature => companyAccount.IsAmazingNewFeatureEnabled,
_ => false
};
or use a throw expression in the default case.
_ => throw new NotImplementedException($"{featureName} not implemented")
Another approach would be to convert the enum into a flags enum and to add a property returning the state as flag set.
[Flags]
public enum FeatureNames {
None = 0,
AmazingFeature = 1,
AmazingNewFeature = 2 // use powers of 2 for all values
}
public class CompanyAccount{
public bool IsAmazingFeatureEnabled { get; set; }
public bool IsAmazingNewFeatureEnabled { get; set; }
public FeatureNames State {
get {
var flags = FeatureNames.None;
if (IsAmazingFeatureEnabled) flags = flags | FeatureNames.AmazingFeature;
if (IsAmazingNewFeatureEnabled) flags = flags | FeatureNames.AmazingNewFeature;
return flags;
}
}
}
Then you can test the state with
if (companyAccount.State.HasFlag(FeatureNames.AmazingFeature)) ...
Using the flag enums, we could turn things around and store the state as flags and then put the logic in the Boolean properties (showing just one property here):
private FeatureNames _state;
public bool IsAmazingFeatureEnabled
{
get => _state.HasFlag(FeatureNames.AmazingFeature);
set => _state = value
? _state | FeatureNames.AmazingFeature
: _state & ~FeatureNames.AmazingFeature;
}
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;
}
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
}
}