Is it possible to set a default value without the body of a property? Preferably with annotations.
[SetTheDefaultValueTo(true)]
public bool IsTrue { get; set; }
[SetTheDefaultValueTo(false)]
public bool IsFalse { get; set; }
public void Something()
{
var isTrue = this.IsTrue;
var isFalse = this.IsFalse;
}
No, there is no built-in way to set the value of a property with metadata. You could use a factory of some sort that would build instances of a class with reflection and then that could set the default values. But in short, you need to use the constructors (or field setters, which are lifted to the constructor) to set the default values.
If you have several overloads for your constructor, you may want to look at constructor chaining.
Using C# 6+, you are able to do something like this...
public string MyValue { get; set; } = "My Default";
Oh, it gets more fun because people have even requested something like this...
// this code won't compile!
public string MyValue {
private string _myValue;
get { return _myValue ?? "My Default"; }
set { _myValue = value; }
}
... the advantage being that you could control the scope of the field to only be accesible in the property code so you don't have to worry about anything else in your class playing with the state without using the getter/setter.
Assign the default property value in the class constructor.
class MyClass
{
public MyClass()
{
IsTrue = true;
IsFalse = false;
}
public bool IsTrue { get; set; }
public bool IsFalse { get; set; }
[...]
public void Something()
{
var isTrue = this.IsTrue;
var isFalse = this.IsFalse;
}
}
If you are using C#5 and earlier, you have to do it in a constructor.
but since C# 6.0, the ability to have auto property initializers is included, and the syntax is:
public int myage { get; set; } = 33;
Old thread.
Looks like Microsoft heard and this feature is available in .Net Framework 4.6+ (C# 6+)
You can use it like
public string MyValue { get; set; } = "My Default";
In this very specific example, you sort of can:
public bool IsFalse { get; set; }
public bool IsTrue
{
get { return !IsFalse; }
set { IsFalse = !value; }
}
public void Something()
{
var isTrue = this.IsTrue;
var isFalse = this.IsFalse;
}
But, in general, no.
Related
I was wondering if there is a way to set a default function for a getter or a setter.
For example, let's say I have this:
public class MyClass
{
public bool IsDirty {get; private set; } = false;
private string _property;
public string Property1
{
get
{
return _property1;
}
set
{
if (value != _property1)
{
_property1 = value;
IsDirty = true;
}
}
}
}
I was wondering if there was a way to do something like this:
public class MyClass
{
public bool IsDirty {get; private set;} = false;
MyClass.defaultSet = { if (value != !_property1) { _property1 = value; IsDirty = true; } };
private string _property1;
public string Property1 { get; set; }
public string Property2 {get; set;}
public string Property3 {get; set;}
//...
}
So that I don't have to do it the first way on this big class I have (~100 properties).
You can reduce the noise by using a helper method like this
private void Set<T>(ref T field, T value)
{
if (!Equals(value, field))
{
field = value;
IsDirty = true;
}
}
Then you can write:
public string Property1
{
get => _property1;
set => Set(ref _property1, value);
}
No, this doesn't exist, for several reasons:
Not every property is going to be a string, so this would need to correctly handle integers, DateTimes, Decimal, etc
Primitive value types are bad enough, but then start throwing in things like Tuples, complex classes (where changing a class member is still get operation on the property itself!), delegates, etc
If you reference a property by it's own name, you're creating a circular reference that will cause a StackOverflowException.
Not every property is going to use the same Property name, so that part of the method is different. You'd need another keyword or argument to the set method.
You need a way to exempt the someBool / IsDirty property.
I want a class/record with protected set and public init access restriction?
To my knowledge this even cannot be done by explicitly implementing a "Set" interface like this:
public interface ISetData<T>
{
T Value { get; set; }
}
public class Data : ISetData<bool>
{
bool ISetData<bool>.Value { get => Value; set => Value = value; } // Error The property Value has no setter
public bool Value { get; init; }
}
Downside is, set functionality is public when using the interface. Not good. (for internal components the interface can be made internal, but that's mostly no option)
Given that only derivations of Data should be able to set data after initialization, the only solution I see is to use an backing field for the property, which is annoying.
Which looks like:
public interface ISetData<T>
{
T Value { get; set; }
}
public class Data : ISetData<bool>
{
bool ISetData<bool>.Value { get => Value; set => _value = value; } // Fine
private bool _value;
public bool Value
{
get { return _value; }
init { }
}
}
That seems odd to me. Would it not be better CLR/c# allows to use access modifiers independently of set/init this like:
public class Data
{
public bool Value { get; init; protected set; }
}
I know this would better be addressed by a feature request, but this is not what this post is about.
So what solutions are available for the scenario "public init, but protected set"?
A simple answer is none.
In C# 9.0, you could have either init or protected set, not both.
You could have a separate property that is protected set and then the public property can be based on your protected property. Example below.
using System;
public class Program
{
public static void Main()
{
var example = new Example{Test = "hello world"};
example.PrintProtectedTest();
Console.WriteLine(example.Test);
example.SetProtectedTest("goodbye world");
Console.WriteLine(example.Test);
}
}
class Example
{
public Example()
{
}
protected string ProtectedTest { get; set; }
public string Test
{
get => ProtectedTest;
init => ProtectedTest = value;
}
public void SetProtectedTest(string test)
{
ProtectedTest = test;
}
public void PrintProtectedTest()
{
Console.WriteLine(ProtectedTest);
}
}
You can run the example here https://dotnetfiddle.net/odGwDj
Having the following classes:
public class DeviceParameter
{
public string Key { get; set; }
public Guid DeviceId { get; set; }
public string Value { get; set; }
}
A device can have a lot of parameters, of different types, but they are all stored in the database as strings.
public abstract class DeviceValueTypedParameter<TValue>
{
public string CodeName { get; }
public TValue Value { get; set; }
public Guid DeviceId { get; set; }
public DeviceValueTypedParameter(string codeName)
{
this.CodeName = codeName;
}
}
DeviceValueTypedParameter is an abstraction, to have a typed value (TValue) used on C# of the parameter value, instead of using the string that we get from the database. There is no heritance between DeviceValueTypedDeviceParameter and DeviceParameter because I want to make the conversion from TValue to string by composition.
public class ArmingStatusParameter : DeviceValueTypedParameter<ArmingStatuses>
{
public const string CODE_NAME = "ArmingStatus";
public ArmingStatusParameter() : base(CODE_NAME)
{
}
}
public enum ArmingStatuses
{
Unknown,
Armed,
Disarmed,
}
ArmingStatusParameter is an example of a typed Parameter that can exist, where the value is an Enum of ArmingStatuses. Other types that can exist are DateTimes, int32, double, etc.
I've already accomplished the conversion from Typed value to string, but now I'm struggling how to properly do the conversion from string to Typed value.
Tried different approaches:
Implicit or Explicit conversion
Extension method
Converter classes for each type that exists
Generic converter class based on TValue type
Option 1: is easy to implement, but violates the POCO of
ArmingStatusParameter. People can forget to implement the implicit/explicit operators and errors will only happen at compile time.
Option 2: violates the Interface segregation principle (ISP), since is needed to access directly the conversion.
Option 3: it works, but people will have to create a lot of classes and the code will be too verbose. For each different parameter, is needed to instance a new {X}TypedParameterConverter.
Option 4: seems the best option, but I am having troubles "in making it work"
I was thinking about something like this:
public interface IDeviceValueTypedParameterConverter
{
bool TryConvert<T, TValue>(DeviceParameter deviceParameter,
DeviceValueTypedParameter<TValue> deviceValueTypedParameter)
where T : DeviceValueTypedParameter<TValue>;
}
public class DeviceValueTypedParameterConverter : IDeviceValueTypedParameterConverter
{
public bool TryConvert<T, TValue>(DeviceParameter inputParameter,
DeviceValueTypedParameter<TValue> outputParameter)
where T : DeviceValueTypedParameter<TValue>
{
bool result = true;
if (inputParameter == null)
{
throw new NullReferenceException($"DeviceValueTypedParameter:'{typeof(T)}' must be initialized first");
}
if (inputParameter.Value is int)
{
result = int.TryParse(inputParameter.Value, out int temp);
outputParameter.Value = (TValue)temp;
}
else if (inputParameter.Value is Enum)
{
// some other code to convert the Enum's
}
// more else ifs one for each type
// (...)
else
{
result = false;
}
outputParameter.DeviceId = inputParameter.DeviceId;
return result;
}
}
Issues:
All the Ifs gives me a warning saying: "The given expression is never of the provided".
Can't make the cast (TValue). It says can't convert int to TValue. The only solution is creating value via reflection?
Here is my attempt to make this work - I am not sure if it violates some details you did not explain (or did explain). Since out parameters can't use polymorphism, I created an interface to represent the common functions across the typed parameter base class. Since there are no static virtual methods, I used object methods and created a result object that will is used if the conversion is possible.
I see no reason for the conversion method to have multiple instances or need an interface, so I created it as a single static method. I used an enum to capture the type of conversion needed for the parameter accessible from the passed in type, and had to do a tricky conversion through object to handle assignment to the out parameter value field, since C# has no type switching capability for assignments. Note this could cause a runtime error if the IsPossible method doesn't properly filter all cases and the ChangeType fails.
public enum ValueParseTypes {
Enum,
DateTime,
Int
}
public interface IDeviceValueTypedDeviceParameter<TValue> {
string CodeName { get; }
TValue Value { get; set; }
Guid DeviceId { get; set; }
ValueParseTypes ParseType { get; set; }
bool IsPossibleValue(DeviceParameter aValue);
}
public abstract class DeviceValueTypedDeviceParameter<TValue> : IDeviceValueTypedDeviceParameter<TValue> {
public string CodeName { get; }
public TValue Value { get; set; }
public Guid DeviceId { get; set; }
public ValueParseTypes ParseType { get; set; }
public DeviceValueTypedDeviceParameter(string codeName, ValueParseTypes parseType) {
this.CodeName = codeName;
this.ParseType = parseType;
}
public virtual bool IsPossibleValue(DeviceParameter aValue) => false;
}
public class ArmingStatusParameter : DeviceValueTypedDeviceParameter<ArmingStatuses> {
public const string CODE_NAME = "ArmingStatus";
public ArmingStatusParameter() : base(CODE_NAME, ValueParseTypes.Enum) {
}
static HashSet<string> ArmingStatusesNames = Enum.GetNames(typeof(ArmingStatuses)).ToHashSet();
public override bool IsPossibleValue(DeviceParameter aValue) => ArmingStatusesNames.Contains(aValue.Value);
}
public enum ArmingStatuses {
Unknown,
Armed,
Disarmed,
}
public class PoweredOnStatusParameter : DeviceValueTypedDeviceParameter<DateTime> {
public const string CODE_NAME = "PoweredOn";
public PoweredOnStatusParameter() : base(CODE_NAME, ValueParseTypes.DateTime) {
}
public override bool IsPossibleValue(DeviceParameter aValue) => DateTime.TryParse(aValue.Value, out _);
}
public class VoltageStatusParameter : DeviceValueTypedDeviceParameter<int> {
public const string CODE_NAME = "PoweredOn";
public VoltageStatusParameter() : base(CODE_NAME, ValueParseTypes.Int) {
}
public override bool IsPossibleValue(DeviceParameter aValue) => Int32.TryParse(aValue.Value, out _);
}
public static class DeviceValueTypedParameterConverter {
public static bool TryConvert<TValue>(DeviceParameter inputParameter, IDeviceValueTypedDeviceParameter<TValue> outputParameter)
where TValue : struct {
if (inputParameter == null)
throw new ArgumentNullException(nameof(inputParameter));
else if (outputParameter == null)
throw new ArgumentNullException(nameof(outputParameter));
bool result = false;
if (outputParameter.IsPossibleValue(inputParameter)) {
outputParameter.DeviceId = inputParameter.DeviceId;
switch (outputParameter.ParseType) {
case ValueParseTypes.Enum:
if (Enum.TryParse(inputParameter.Value, out TValue typedValue)) {
outputParameter.Value = typedValue;
result = true;
}
break;
case ValueParseTypes.DateTime:
if (DateTime.TryParse(inputParameter.Value, out var dtValue)) {
outputParameter.Value = (TValue)Convert.ChangeType(dtValue, typeof(TValue));
result = true;
}
break;
case ValueParseTypes.Int:
if (Int32.TryParse(inputParameter.Value, out var intValue)) {
outputParameter.Value = (TValue)Convert.ChangeType(intValue, typeof(TValue));
result = true;
}
break;
}
}
return result;
}
}
Now you can use it like so:
var as_tv = new DeviceParameter() {
Key = "testkey",
DeviceId = new Guid(),
Value = "Armed"
};
var asp = new ArmingStatusParameter();
if (DeviceValueTypedParameterConverter.TryConvert<ArmingStatuses>(as_tv, asp)) {
// work with asp
}
var po_tv = new DeviceParameter() {
Key = "testkey2",
DeviceId = new Guid(),
Value = "4/15/2019 17:36"
};
var pop = new PoweredOnStatusParameter();
if (DeviceValueTypedParameterConverter.TryConvert<DateTime>(po_tv, pop)) {
// work with pop
}
var v_tv = new DeviceParameter() {
Key = "testkey3",
DeviceId = new Guid(),
Value = "17"
};
var vp = new VoltageStatusParameter();
if (DeviceValueTypedParameterConverter.TryConvert<int>(v_tv, vp)) {
// work with vp
}
how can i create a method that get's an object to read only purpose
public class Person
{
public string Name;
}
public void RunMe(Person p)
{
p.Name="XXXX";
}
var p =new Person();
p.Name="YYYY";
RunMe(p);
Console.WriteLine(p.Name);
I am getting XXXX. but i want that the person object will not change it value.
you can use interfaces to restrict the access. It is also better to pass interfaces instead of concrete objects as parameters to methods.
public interface IReadablePerson
{
string Name { get; }
}
public interface IWritablePerson
{
string Name { set; }
}
public class Person : IReadablePerson, IWritablePerson
{
public string Name { get; set; }
}
and then have a method like this
public void RunMe(IReadablePerson p)
{
p.Name = "XXXX"; //compile time error!!!
}
The way to do this is via the get and set accessors, just don't define a set:
public String Name { get; }
This will make a property that you can treat exactly like a normal field for your purposes. Underneath properties are a little more complex using methods to set a backing field which you can read about on msdn
If you need to be able to set the property just once then define the set as private and pass the parameter into the constructor:
public class Person
{
public Person(String name)
{
this.Name = name;
}
public String Name { get; private set; }
}
Classes in C# are reference types, so there's no way to do what you want to do if Person is a class.
You could make it a value type (by making it a struct) in which case, a copy of the object would be passed in, but that may take implications at some other points in your program, so be wary if you do it.
It seems that you want to somehow be able to lock the member. One option would be to make the "set" dependent on another member like this:
public class Name
{
public bool Locked { get; set; }
private string name;
public string Name
{
get { return this.name; }
set
{
if(!this.Locked)
this.name = val;
}
}
}
Edit: Alternate method for making lock permanent.
public class Person
{
private bool locked = false;
public void Lock()
{
this.locked = true;
}
public bool Locked
{
get { return this.locked; }
}
// add same Name member as above
}
Edit: Yet ANOTHER way to lock, using a key.
private object key = null;
public bool Locked
{ get { return this.key != null; } }
public void Lock(object obj)
{
if (this.key == null)
{
this.key = obj;
}
}
public void Unlock(object obj)
{
if (this.key == obj)
{
this.key = null;
}
}
You can throw an exception if you want if trying to unlock with the wrong key object.
The behaviour described after the first setting of the property is this:
private string _name;
public string Name
{
get { return _name; }
set { // no setting }
}
This is NOT A GOOD PRACTICE.
you create unexpected behaviour for properties (if this is a public class).
Any consuming assembly cannot view the body of the get and set methods would expect a set method to behave a sertain way (setting a value).
This kind of behaviour should be put in a seperate set method.
This way you can see if it changed, throw an exception if you want, or return true if it changed.
Then you can still use the property for getting the value.
private bool _locked;
public string Name { get; private set;}
public boolSetName(string value)
{
bool hasChanged = false;
if(!_locked)
{
Name = value;
_locked = true;
hasChanged = true;
}
return hasChanged
}
I have an object model that has a property like this:
public class SomeModel
{
public string SomeString { get; set; }
public void DoSomeWork()
{
....
}
}
I want the DoSomeWork function to execute automatically after the SomeString property changes. I tried this but it's not working:
public string SomeString { get; set { DoSomeWork(); } }
What's the correct syntax?
Use a private field instead, like this ...
public class SomeModel
{
private string someString = "";
public string SomeString {
get { return this.someString; }
set {
this.someString = value;
this.DoSomeWork();
}
}
public void DoSomeWork()
{
....
}
}
You can't do this with automatic properties - you'll have to create a "manual" property backed by a field.
private string _someString;
public string SomeString
{
get { return _someString; }
set
{
_someString = value;
DoSomeWork();
}
}
If you really can't deal with this boilerplate (say you'd have to do this hundreds of times), consider using an AOP framework like PostSharp to implement this on your behalf - you'd just need to declare an automatic property and an attribute to get the binary rewriter to implement the desired scheme.
This will work...
private string _someString;
public string SomeString { get { return _someString; } set { _someString = value; DoSomeWork(); } }
private string _someString;
public string SomeString
{
get
{
return _someString;
}
set
{
DoSomeWork();
_someString = value;
}
}
C# team has introduced the auto-implement properties in C# 3.0. with the logic of minimizing the model making which is backed by an anonymous field created by compiler. this one is used when you don't need to implement any additional logic on a property of an object class. so it just followed as.
public string Name{ get; set;}// auto-implemented property. no additional logic.
if we want to add some logic as you want to add one function. we must be writing a manual property backed by a private field as like below.
private string _Name;
public string Name
{
get {return _Name;}
set {
_Name=value;
DoSomething(); //Additional logic implemented.
}
}