Take the following struct class:
public struct SingleWraper
{
private double _myValue;
public double MyValue
{
get { return _myValue; }
set { _myValue = value; }
}
public void SetMyValue(double myValue)
{
_myValue = myValue;
}
}
public struct DoubleWraper
{
public SingleWraper SingWraper { get; set; }
public void SetMyValue(double singleVa)
{
SingWraper.SetMyValue(singleVa);
}
}
Run the following test:
[Test]
public void SetMyValue()
{
var singleWraper = new DoubleWraper();
singleWraper.SetMyValue(10);
Assert.AreEqual(10,singleWraper.SingWraper.MyValue);
}
It fails.
However, if you don't use automatic property for DoubleWraper, i.e, you expand the field as below:
public struct DoubleWraper
{
private SingleWraper _singWraper;
public SingleWraper SingWraper
{
get { return _singWraper; }
set { _singWraper = value; }
}
public void SetMyValue(double singleVa)
{
_singWraper.SetMyValue(singleVa);
}
}
Then the test will pass.
Why this is so?
It is here:
_singWraper.SetMyValue(singleVa);
vs:
SingWraper.SetMyValue(singleVa);
In the second, you access a property, therefore you clone the struct; essentially this is the same as:
var clonedAndIndependentValue = SingWraper; // getter
clonedAndIndependentValue.SetMyValue(singleVa);
Note we've updated a different struct value; contrast to field access, which talks to the existing struct value.
Yet another example of why mutable structs are evil. DON'T DO IT. Make the struct immutable (no Set* methods, property setters, or other shenanigans). Or use a class.
Related
The main purpose is to show intellisense when setting the property. It would be great if I could do it via an attribute like the image below.
The property should remain a string(not enum or struct) so that Mongo's BsonSerializer can serialize it properly. Here is an example of what it might look like:
To help other developers on the team know possible (but not exlusive) values they can use for the Type field Code Completion should display values that can be used as shown below:
(Edited) I was able to solve this by creating my own type
public class SkinType:StringType<SkinType>
{
public SkinType(string value)
{
Value = value;
}
public SkinType()
{
}
public static implicit operator string(SkinType d)
{
return d.Value;
}
public static implicit operator SkinType(string d)
{
return new SkinType(d);
}
public const string StringValue = nameof(StringValue);
public const string Color = nameof(Color);
}
Now I get intellisense for my Type property and Mongo knows how to serialize it.
Here is how I use it:
public class Skin : ServiceMongoIdentity
{
//removed some properties for brevity.
[BsonIgnoreIfDefault]
[BsonDefaultValue(SkinType.StringValue)]
public SkinType Type { get; set; } = SkinType.StringValue;
}
Here is how the StringType base class is defined. I had to make Value public because Generics cannot have constructors with parameters
public abstract class StringType<T> where T :StringType<T>,new()
{
[ReadOnly(true)]
public string Value;
public T FromString(string d)
{
return new T
{
Value = d
};
}
public override bool Equals(object obj)
{
return obj?.ToString() == Value;
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override string ToString()
{
return Value;
}
}
Consider this code:
public string Variable1 { get; set;}
public int Variable2 { get; set;}
public void Function()
{
// Has been Variable1 Initialized?
}
Inside the function, I want to know if a value has been sent to Variable1 & Variable2, prior to the function call,
even if the DEFAULT values have been sent, that's ok (null for string & 0 for int)
Consider using a simple wrapper like this:
public struct AssignableProperty<T>
{
private T _value;
public T Value
{
get { return _value; }
set
{
WasAssigned = true;
_value = value;
}
}
public bool WasAssigned { get; private set; }
public static implicit operator AssignableProperty<T>(T data)
{
return new AssignableProperty<T>() { Value = data };
}
public static bool operator ==(AssignableProperty<T> initial, T data)
{
return initial.Value.Equals(data);
}
public static bool operator !=(AssignableProperty<T> initial, T data)
{
return !initial.Value.Equals(data);
}
public override string ToString()
{
return Value.ToString();
}
}
Then your class'll look like this:
public class Test
{
public AssignableProperty<string> Variable1 { get; set; }
public AssignableProperty<int> Variable2 { get; set; }
public void Function()
{
if(Variable1.WasAssigned&&Variable2.WasAssigned)
//do stuff
}
}
You can go further and add throw Exception or contract to getter, so if somebody'll try to access uninitialized value it'll throw an exception or show you warning
Some basics about default value in C#:
When an instance of a class (or struct) is created, all fields are initialized to their respective default value.
For reference types, it will be null. For value types, it will be equivalent to 0. This is easily explains as the memory management ensures that new allocated memory is initialized to 0x0 bytes.
Auto-properties hide the generated field, but there is one. So the same rules apply.
Now to answer your question, the best way to make sure that values are initialized is to make a constructor with one parameter for each field/property and to hide the default constructor with no parameters:
public Yourtype(String param1, Int32 param2)
{
this.Variable1 = param1;
this.Variable2 = param2;
}
private Yourtype() { }
Other alternatives is described in #Sean and #Alex answers if only a subset of properties/fields needs to be initialized/checked. But this hides some overhead (one bool for each property/field and some indirection).
For the reference types you'll need to add a flag:
string m_Variable1;
bool m_IsVariable1Set;
public string Variable1
{
get{return m_Variable1;}
set{m_IsVariable1Set = true; m_Variable1 = value;}
}
For the value types you can use a nullable value
int? m_Variable2;
int Variable2
{
get{return m_Variable2.GetValueOrDefault();}
set{m_Variable2 = value;}
}
Which you can then check to see if it's been set by using m_Variable2.HasValue.
Well you can simply do a check on both variables to see if they have any value assigned to them in your function
public void Function()
{
if (String.IsNullOrEmpty(Variable1) && Variable2 ==0 )
{
// Variables are not assigned
}
}
I'm trying to create a class which takes value a as a parameters in it's constructor.
It has a private member variable which stores this value. The value should not be changed afterwards.
Here's what I have, it works but I don't think it's the best solution out there:
internal class Foo
{
private int a;
public int A
{
get
{
return this.a;
}
}
public Foo(int a)
{
this.a = a;
}
}
So this way you can not access a from outside of the class, and A-property only has a get method. However, you can still change a from inside the class, and using a property which only returns one variable and nothing else feels stupid.
Am I doing this right, or is there a way to improve my code/more proper way to do this?
Additionally declare your private field readonly and you're there!
public class Foo
{
public Foo(int bar)
{
this.bar = bar;
}
public int Bar
{
get
{
return bar;
}
}
private readonly int bar;
}
“In C# 6 and later, you can initialize auto-implemented properties similarly to fields”. Just like you can initialize a readonly field in a constructor, you can initialize a get-only auto-implemented property in a constructor. Thus, the following now compiles:
public class Class1
{
public int A { get; }
public Class1(int a)
{
A = a;
}
}
…and the following yields an error:
public class Class1
{
public int A { get; }
public Class1(int a)
{
A = a;
}
public void Mutate()
{
// Class1.cs(11,9,11,10): error CS0200: Property or indexer 'Class1.A' cannot be assigned to -- it is read only
A++;
}
}
I like it—you get the terseness of field initialization with the interface/OOP-friendliness of properties.
internal class Foo
{
private readonly int _a;
public int A
{
get
{
return _a;
}
}
public Foo(int a)
{
_a = a;
}
}
This should do it.
If my understanding of the internal workings of this line is correct:
public int MyInt { get; set; }
Then it behind the scenes does this:
private int _MyInt { get; set; }
Public int MyInt {
get{return _MyInt;}
set{_MyInt = value;}
}
What I really need is:
private bool IsDirty { get; set; }
private int _MyInt { get; set; }
Public int MyInt {
get{return _MyInt;}
set{_MyInt = value; IsDirty = true;}
}
But I would like to write it something like:
private bool IsDirty { get; set; }
public int MyInt { get; set{this = value; IsDirty = true;} }
Which does not work. The thing is some of the objects I need to do the IsDirty on have dozens of properties and I'm hoping there is a way to use the auto getter/setter but still set IsDirty when the field is modified.
Is this possible or do I just have to resign myself to tripling the amount of code in my classes?
You'll need to handle this yourself:
private bool IsDirty { get; set; }
private int _myInt; // Doesn't need to be a property
Public int MyInt {
get{return _myInt;}
set{_myInt = value; IsDirty = true;}
}
There is no syntax available which adds custom logic to a setter while still using the automatic property mechanism. You'll need to write this with your own backing field.
This is a common issue - for example, when implementing INotifyPropertyChanged.
Create an IsDirty decorator (design pattern) to wrap some your properties requiring the isDirty flag functionality.
public class IsDirtyDecorator<T>
{
public bool IsDirty { get; private set; }
private T _myValue;
public T Value
{
get { return _myValue; }
set { _myValue = value; IsDirty = true; }
}
}
public class MyClass
{
private IsDirtyDecorator<int> MyInt = new IsDirtyDecorator<int>();
private IsDirtyDecorator<string> MyString = new IsDirtyDecorator<string>();
public MyClass()
{
MyInt.Value = 123;
MyString.Value = "Hello";
Console.WriteLine(MyInt.Value);
Console.WriteLine(MyInt.IsDirty);
Console.WriteLine(MyString.Value);
Console.WriteLine(MyString.IsDirty);
}
}
You can make it simple or complex. It depends on how much work you want to invest. You can use aspect oriented programming to add the aspect via an IL weaver into the IL code with e.g. PostSharp.
Or you can create a simple class that does handle the state for your property. It is so simple that the former approach only pays off if you have really many properties to handle this way.
using System;
class Dirty<T>
{
T _Value;
bool _IsDirty;
public T Value
{
get { return _Value; }
set
{
_IsDirty = true;
_Value = value;
}
}
public bool IsDirty
{
get { return _IsDirty; }
}
public Dirty(T initValue)
{
_Value = initValue;
}
}
class Program
{
static Dirty<int> _Integer;
static int Integer
{
get { return _Integer.Value; }
set { _Integer.Value = value; }
}
static void Main(string[] args)
{
_Integer = new Dirty<int>(10);
Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
Integer = 15;
Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
}
}
Another possibility is to use a proxy class which is generated at runtime which does add the aspect for you. With .NET 4 there is a class that does handle this aspect already for you. It is called ExpandObject which does notify you via an event when a property changes. The nice things is that ExpandoObject allows you to define at runtime any amount of properties and you get notifications about every change of a property. Databinding with WPF is very easy with this type.
dynamic _DynInteger = new ExpandoObject();
_DynInteger.Integer = 10;
((INotifyPropertyChanged)_DynInteger).PropertyChanged += (o, e) =>
{
Console.WriteLine("Property {0} changed", e.PropertyName);
};
Console.WriteLine("value: {0}", _DynInteger.Integer );
_DynInteger.Integer = 20;
Console.WriteLine("value: {0}", _DynInteger.Integer);
Yours,
Alois Kraus
I'm going to add on to Simon Hughes' answer. I propose the same thing, but add a way to allow the decorator class to update a global IsDirty flag automatically. You may find it to be less complex to do it the old-fashioned way, but it depends on how many properties you're exposing and how many classes will require the same functionality.
public class IsDirtyDecorator<T>
{
private T _myValue;
private Action<bool> _changedAction;
public IsDirtyDecorator<T>(Action<bool> changedAction = null)
{
_changedAction = changedAction;
}
public bool IsDirty { get; private set; }
public T Value
{
get { return _myValue; }
set
{
_myValue = value;
IsDirty = true;
if(_changedAction != null)
_changedAction(IsDirty);
}
}
}
Now you can have your decorator class automatically update some other IsDirty property in another class:
class MyObject
{
private IsDirtyDecorator<int> _myInt = new IsDirtyDecorator<int>(onValueChanged);
private IsDirtyDecorator<int> _myOtherInt = new IsDirtyDecorator<int>(onValueChanged);
public bool IsDirty { get; private set; }
public int MyInt
{
get { return _myInt.Value; }
set { _myInt.Value = value; }
}
public int MyOtherInt
{
get { return _myOtherInt.Value; }
set { _myOtherInt.Value = value; }
}
private void onValueChanged(bool dirty)
{
IsDirty = true;
}
}
I have created a custom Property<T> class to do common operations like that. I haven't used it thoroughly yet though, but it could be used in this scenario.
Code can be found here: http://pastebin.com/RWTWNNCU
You could use it as follows:
readonly Property<int> _myInt = new Property<int>();
public int MyInt
{
get { return _myInt.GetValue(); }
set { _myInt.SetValue( value, SetterCallbackOption.OnNewValue, SetDirty ); }
}
private void SetDirty( int oldValue, int newValue )
{
IsDirty = true;
}
The Property class handles only calling the passed delegate when a new value is passed thanks to the SetterCallbackOption parameter. This is default so it can be dropped.
UPDATE:
This won't work apparently when you need to support multiple types (besides int), because the delegate won't match then. You could ofcourse always adjust the code to suit your needs.
This works:
using System;
using ConstraintSet = System.Collections.Generic.Dictionary<System.String, double>;
namespace ConsoleApplication2
{
class test
{
public ConstraintSet a { get; set; }
public test()
{
a = new ConstraintSet();
}
static void Main(string[] args)
{
test abc = new test();
Console.WriteLine("done");
}
}
}
This does not:
using System;
using ConstraintSet = System.Collections.Generic.Dictionary<System.String, double>;
namespace ConsoleApplication2
{
class test
{
public ConstraintSet a { get { return a; } set { a = value; } }
public test()
{
a = new ConstraintSet();
}
static void Main(string[] args)
{
test abc = new test();
Console.WriteLine("done");
}
}
}
I get a stack overflow exception on a's setter in the second class and I do not know why. I cannot use the first form because it is not supported by the Unity game engine.
When you write a = value, you are calling the property setter again.
In order to use non-automatic properties, you need to create a separate private backing field, like this:
ConstraintSet a;
public ConstraintSet A { get { return a; } set { a = value; } }
You haven't declared a backing variable - you've just got a property whose getters and setters call themselves. It's not clear to me why the first form isn't supported by Unity - which means it's possible that the equivalent won't be supported either, but it's basically this:
private ConstraintSet aValue;
public ConstraintSet a { get { return aValue; } set { aValue = value; } }
I'd normally have a more conventional name, of course - which means you can get away without the "value` bit:
private ConstraintSet constraints;
public ConstraintSet Constraints
{
get { return constraints; }
set { constraints = value; }
}
To give a bit more detail as to why your current second form is throwing a StackOverflowException, you should always remember that properties are basically methods in disguise. Your broken code looks like this:
public ConstraintSet get_a()
{
return get_a();
}
public void set_a(ConstraintSet value)
{
set_a(value);
}
Hopefully it's obvious why that version is blowing the stack. The amended version just sets a variable instead of calling the property again, so it looks like this when expanded:
private ConstraintSet aValue;
public ConstraintSet get_a()
{
return aValue;
}
public void set_a(ConstraintSet value)
{
aValue = value;
}
You cannot use the same variable name inside the getter and setter. This will cause it to call itself and will eventually lead to a stack overflow. Too much recursion.
You'll need a backing variable:
private ConstraintSet _a;
public ConstraintSet a { get { return _a; } set { _a = value; } }
You need a private backing variable in your public property:
private ConstraintSet _a;
public ConstraintSet a { get { return _a; } set { _a = value; } }