I was confronted with a StackOverflowException that made me discover that DependencyObject does not handle equality correctly ?!
When the DependencyProperty is of Type Object it will allways use Reference.Equals. This causes to fire PropertyChanged everytime for strings and valuetypes when the same value gets applied.
If you take a look at
DependencyObject.Equals(DependencyProperty dp, object value1, object
value2)
https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/DependencyObject.cs,3453
/// <summary>
/// Helper method to compare two DP values
/// </summary>
private bool Equals(DependencyProperty dp, object value1, object value2)
{
if (dp.IsValueType || dp.IsStringType)
{
// Use Object.Equals for Strings and ValueTypes
return Object.Equals(value1, value2);
}
else
{
// Use Object.ReferenceEquals for all other ReferenceTypes
return Object.ReferenceEquals(value1, value2);
}
}
A simple way to reproduce:
public static readonly DependencyProperty ObjValueProperty = DependencyProperty.Register(nameof(ObjValue), typeof(object), typeof(MainWindow), new PropertyMetadata(default(object)));
public object ObjValue
{
get
{
return GetValue(ObjValueProperty);
}
set
{
SetValue(ObjValueProperty, value);
}
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if(e.Property == ObjValueProperty) { /*Breakpoint here*/ }
}
...
ObjValue = 7;
ObjValue = 7;
So, is this desired behaviour or a bug?
I don't think this is a bug. Its just the way dotnet handles objects. It is same same if you try it without the context of DependencyProperties:
I created a small console application:
object v1 = 7;
object v2 = 7;
if (v1 == v2) Console.Write("are the same"); else Console.Write("are different");
I read "are different" in console. So generally, if objects are evaluated for equality then always by ReferenceEquals (even if they are boxed value types).
Related
I'm using reflection to loop through a Type's properties and set certain types to their default. Now, I could do a switch on the type and set the default(Type) explicitly, but I'd rather do it in one line. Is there a programmatic equivalent of default?
In case of a value type use Activator.CreateInstance and it should work fine.
When using reference type just return null
public static object GetDefault(Type type)
{
if(type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
In the newer version of .net such as .net standard, type.IsValueType needs to be written as type.GetTypeInfo().IsValueType
Why not call the method that returns default(T) with reflection ? You can use GetDefault of any type with:
public object GetDefault(Type t)
{
return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
}
public T GetDefaultGeneric<T>()
{
return default(T);
}
You can use PropertyInfo.SetValue(obj, null). If called on a value type it will give you the default. This behavior is documented in .NET 4.0 and in .NET 4.5.
If you're using .NET 4.0 or above and you want a programmatic version that isn't a codification of rules defined outside of code, you can create an Expression, compile and run it on-the-fly.
The following extension method will take a Type and get the value returned from default(T) through the Default method on the Expression class:
public static T GetDefaultValue<T>()
{
// We want an Func<T> which returns the default.
// Create that expression here.
Expression<Func<T>> e = Expression.Lambda<Func<T>>(
// The default value, always get what the *code* tells us.
Expression.Default(typeof(T))
);
// Compile and return the value.
return e.Compile()();
}
public static object GetDefaultValue(this Type type)
{
// Validate parameters.
if (type == null) throw new ArgumentNullException("type");
// We want an Func<object> which returns the default.
// Create that expression here.
Expression<Func<object>> e = Expression.Lambda<Func<object>>(
// Have to convert to object.
Expression.Convert(
// The default value, always get what the *code* tells us.
Expression.Default(type), typeof(object)
)
);
// Compile and return the value.
return e.Compile()();
}
You should also cache the above value based on the Type, but be aware if you're calling this for a large number of Type instances, and don't use it constantly, the memory consumed by the cache might outweigh the benefits.
Why do you say generics are out of the picture?
public static object GetDefault(Type t)
{
Func<object> f = GetDefault<object>;
return f.Method.GetGenericMethodDefinition().MakeGenericMethod(t).Invoke(null, null);
}
private static T GetDefault<T>()
{
return default(T);
}
This is optimized Flem's solution:
using System.Collections.Concurrent;
namespace System
{
public static class TypeExtension
{
//a thread-safe way to hold default instances created at run-time
private static ConcurrentDictionary<Type, object> typeDefaults =
new ConcurrentDictionary<Type, object>();
public static object GetDefaultValue(this Type type)
{
return type.IsValueType
? typeDefaults.GetOrAdd(type, Activator.CreateInstance)
: null;
}
}
}
The chosen answer is a good answer, but be careful with the object returned.
string test = null;
string test2 = "";
if (test is string)
Console.WriteLine("This will never be hit.");
if (test2 is string)
Console.WriteLine("Always hit.");
Extrapolating...
string test = GetDefault(typeof(string));
if (test is string)
Console.WriteLine("This will never be hit.");
I do the same task like this.
//in MessageHeader
private void SetValuesDefault()
{
MessageHeader header = this;
Framework.ObjectPropertyHelper.SetPropertiesToDefault<MessageHeader>(this);
}
//in ObjectPropertyHelper
public static void SetPropertiesToDefault<T>(T obj)
{
Type objectType = typeof(T);
System.Reflection.PropertyInfo [] props = objectType.GetProperties();
foreach (System.Reflection.PropertyInfo property in props)
{
if (property.CanWrite)
{
string propertyName = property.Name;
Type propertyType = property.PropertyType;
object value = TypeHelper.DefaultForType(propertyType);
property.SetValue(obj, value, null);
}
}
}
//in TypeHelper
public static object DefaultForType(Type targetType)
{
return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
}
Equivalent to Dror's answer but as an extension method:
namespace System
{
public static class TypeExtensions
{
public static object Default(this Type type)
{
object output = null;
if (type.IsValueType)
{
output = Activator.CreateInstance(type);
}
return output;
}
}
}
The Expressions can help here:
private static Dictionary<Type, Delegate> lambdasMap = new Dictionary<Type, Delegate>();
private object GetTypedNull(Type type)
{
Delegate func;
if (!lambdasMap.TryGetValue(type, out func))
{
var body = Expression.Default(type);
var lambda = Expression.Lambda(body);
func = lambda.Compile();
lambdasMap[type] = func;
}
return func.DynamicInvoke();
}
I did not test this snippet, but i think it should produce "typed" nulls for reference types..
Slight adjustments to #Rob Fonseca-Ensor's solution: The following extension method also works on .Net Standard since I use GetRuntimeMethod instead of GetMethod.
public static class TypeExtensions
{
public static object GetDefault(this Type t)
{
var defaultValue = typeof(TypeExtensions)
.GetRuntimeMethod(nameof(GetDefaultGeneric), new Type[] { })
.MakeGenericMethod(t).Invoke(null, null);
return defaultValue;
}
public static T GetDefaultGeneric<T>()
{
return default(T);
}
}
...and the according unit test for those who care about quality:
[Fact]
public void GetDefaultTest()
{
// Arrange
var type = typeof(DateTime);
// Act
var defaultValue = type.GetDefault();
// Assert
defaultValue.Should().Be(default(DateTime));
}
/// <summary>
/// returns the default value of a specified type
/// </summary>
/// <param name="type"></param>
public static object GetDefault(this Type type)
{
return type.IsValueType ? (!type.IsGenericType ? Activator.CreateInstance(type) : type.GenericTypeArguments[0].GetDefault() ) : null;
}
This should work:
Nullable<T> a = new Nullable<T>().GetValueOrDefault();
If you already create an object, you can try...
var yourObj = new yourObj();
var properties = yourObj.GetType().GetProperties();
foreach (var p in properties)
{
// you can get default value for each property
var defaultValue = p.GetValue(yourObj, null);
}
There is a way to reset application settings with Settings.Default.Reset()
Is there a way to reset only one property? Something like
Settings.Default.Properties["MyPropertyName"].Reset();
You can use the Settings.Default.Properties["MyProperty"].DefaultValue to obtain the default value for the property, and set the property value to that.
It's the PropertyValue that's need to be set in combinaison of Deserialized (the order matter) :
public void ResetOneSetting(string propertyName)
{
SettingsPropertyValue propertyToReset = Settings.Default.PropertyValues.OfType<SettingsPropertyValue>().FirstOrDefault(p => p.Name == propertyName);
if (propertyToReset != null)
{
propertyToReset.PropertyValue = propertyToReset.Property.DefaultValue;
propertyToReset.Deserialized = false;
}
}
Found solution when reading .NET source code:
Settings.Default.PropertyValues["MyPropertyName"].SerializedValue = Settings.Default.Properties["MyPropertyName"].DefaultValue;
Settings.Default.PropertyValues["MyPropertyName"].Deserialized = false;
In my case (.NET Framework 4.6.1, with a System.Drawing.Color as setting), I also had to re-assign the value in Settings.Default, otherwise the change seemed to be ignored:
var propertyValue = Settings.Default.PropertyValues["myPropertyName"];
propertyValue.PropertyValue = propertyValue.Property.DefaultValue;
propertyValue.Deserialized = false;
Settings.Default["myPropertyName"] = propertyValue.PropertyValue;
I use the following code to reset a setting in my program. It takes advantage of reflection and allows you to pass a property directly instead of you manually writing out a properties name. It can be used like ResetToDefaultValue(TestSettings.Default, x => x.TextFieldStuff);
The advantage of this is that it does not all your settings are in Settings but some might be stored in different settings files.
//Way to use
//ResetToDefaultValue(TestSettings.Default, x => x.TextFieldStuff);
private static void ResetToDefaultValue<T1, T2>(T1 settings, Expression<Func<T1, T2>> property, bool saveOnReset = true)
{
if (IsSameOrSubclass(typeof(ApplicationSettingsBase), settings.GetType()))
{
ApplicationSettingsBase s = settings as ApplicationSettingsBase;
if (s != null)
{
MemberInfo member = GetMemberInfo(property);
if (!s.PropertyValues[member.Name].UsingDefaultValue)
{
s.PropertyValues[member.Name].PropertyValue = s.PropertyValues[member.Name].Property.DefaultValue;
s.PropertyValues[member.Name].Deserialized = false;
s[member.Name] = s.PropertyValues[member.Name].PropertyValue; //Triggers the property changed
if (saveOnReset)
{
s.Save();
}
}
}
}
}
//Way to use
//GetMemberInfo((TestSettings testSettings) => testSettings.TextFieldStuff);
private static MemberInfo GetMemberInfo<T1, T2>(Expression<Func<T1, T2>> expression)
{
if (IsSameOrSubclass(typeof(MemberExpression), expression.Body.GetType()))
{
MemberExpression member = (MemberExpression)expression.Body;
return member.Member;
}
throw new ArgumentException(#"Expression is not a member access", nameof(expression));
}
private static bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
return potentialDescendant.IsSubclassOf(potentialBase)
|| potentialDescendant == potentialBase;
}
Or if you are using C# 7.1 or greater, you can use feature matching.
//Way to use
//ResetToDefaultValue(TestSettings.Default, x => x.TextFieldStuff);
private static void ResetToDefaultValue<T1, T2>(T1 settings, Expression<Func<T1, T2>> property, bool saveOnReset = true)
{
//Requires C# >= 7.1
if (settings is ApplicationSettingsBase s)
{
MemberInfo member = GetMemberInfo(property);
if (!s.PropertyValues[member.Name].UsingDefaultValue)
{
s.PropertyValues[member.Name].PropertyValue = s.PropertyValues[member.Name].Property.DefaultValue;
s.PropertyValues[member.Name].Deserialized = false;
s[member.Name] = s.PropertyValues[member.Name].PropertyValue;
if (saveOnReset)
{
s.Save();
}
}
}
}
//Way to use
//GetMemberInfo((TestSettings testSettings) => testSettings.TextFieldStuff);
private static MemberInfo GetMemberInfo<T1, T2>(Expression<Func<T1, T2>> expression)
{
//Requires C# >= 7.0
if (expression.Body is MemberExpression member)
{
return member.Member;
}
throw new ArgumentException(#"Expression is not a member access", nameof(expression));
}
While I checked out the answers from #dalleria and #nikita, I run into the problem that
the PropertyValue (SettingsPropertyValue) got defaulted unexpectely when I tried to get a deep copy of DefaultValue (SettingsProperty) or PropertyValue (SettingsPropertyValue) or any other same typed value.
So here is my short implementation of a deep copy function that is part of a class, so I apologize for not refactoring it to a extension or tool method.
private SettingsPropertyValue settingsPropertyValue; // (ex. Settings.Default.PropertyValues["anyPropertyName"])
private SettingsProperty settingsProperty
=> settingsPropertyValue.Property;
/// <summary>
/// Create a deep copy of <paramref name="value"/>.
/// </summary>
/// <param name="value">
/// Should be a deserialized value (ex. <see cref="SettingsPropertyValue.PropertyValue"/>)
/// or a serialized value (ex. <see cref="SettingsProperty.DefaultValue"/>).
/// </param>
/// <param name="isDeserialized">Indicates whether <paramref name="value"/> is deserialized or serialized.</param>
private PropertyType copyValue<PropertyType>(object value, bool isDeserialized)
{
var temporaryPropertyValue = settingsPropertyValue.PropertyValue;
settingsPropertyValue.PropertyValue = value;
if (isDeserialized)
// We have to reassign, otherwise PropertyValue/SerializedValue of SettingsPropertyValue may be defaulted
settingsPropertyValue.SerializedValue = settingsPropertyValue.SerializedValue;
settingsPropertyValue.Deserialized = false;
var propertyValue = (PropertyType)settingsPropertyValue.PropertyValue;
settingsPropertyValue.PropertyValue = temporaryPropertyValue;
return propertyValue;
}
You can then reset a single property of an instance of ApplicationSettings/SettingsBase with these lines:
SettingsBase settings; // (ex. Settings.Default)
public void SetOriginalFromDefault()
{
object defaultValue = settingsProperty.DefaultValue;
defaultValue = copyValue(defaultValue, false);
// We want to set the new value. It also triggers the INotifyPropertyChanged of settings, if the instance is from type ApplicationSettings
settings[settingsProperty.Name] = defaultValue;
}
I added a ValidateValueCallback to a DependencyProperty called A. Now in the validate callback, A shall be compared to the value of a DependencyProperty called B. But how to access the value of B in the static ValidateValueCallback method validateValue(object value)? Thanks for any hint!
Sample code:
class ValidateTest : DependencyObject
{
public static DependencyProperty AProperty = DependencyProperty.Register("A", typeof(double), typeof(ValidateTest), new PropertyMetadata(), validateValue);
public static DependencyProperty BProperty = DependencyProperty.Register("B", typeof(double), typeof(ValidateTest));
static bool validateValue(object value)
{
// Given value shall be greater than 0 and smaller than B - but how to access the value of B?
return (double)value > 0 && value <= /* how to access the value of B ? */
}
}
Validation callbacks are used as sanity checks for the given input value against a set of static constraints. In your validation callback, checking for a positive value is a correct use of the validation, but checking against another property is not. If you need to ensure a given value is less than a dependent property, you should use property coercion, like so:
public static DependencyProperty AProperty = DependencyProperty.Register("A", typeof(double), typeof(ValidateTest), new PropertyMetadata(1.0, null, coerceValue), validateValue);
public static DependencyProperty BProperty = DependencyProperty.Register("B", typeof(double), typeof(ValidateTest), new PropertyMetaData(bChanged));
static object coerceValue(DependencyObject d, object value)
{
var bVal = (double)d.GetValue(BProperty);
if ((double)value > bVal)
return bVal;
return value;
}
static bool validateValue(object value)
{
return (double)value > 0;
}
While this won't throw an exception if you set A > B (like the ValidationCallback does), this is actually the desired behavior. Since you don't know the order in which the properties are set, you should therefore support the properties being set in any order.
We also need to tell WPF to coerce the value of property A if the value of B changes, as the coerced value could change:
static void bChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(AProperty);
}
(Using VS 2010 Beta 2 - .Net 4.0 B2 Rel)
I have a class, MyTable, derived from BindingList where S is a struct. S is made up of several other structs, for example:
public class MyTable<S>:BindingList<S> where S: struct
{
...
}
public struct MyStruct
{
public MyReal r1;
public MyReal r2;
public MyReal R1 {get{...} set{...}}
public MyReal R2 {get{...} set{...}}
...
}
public struct MyReal
{
private Double d;
private void InitFromString(string) {this.d = ...;}
public MyReal(Double d) { this.d = d;}
public MyReal(string val) { this.d = default(Double); InitFromString(val);}
public override string ToString() { return this.real.ToString();}
public static explicit operator MyReal(string s) { return new MyReal(s);}
public static implicit operator String(MyReal r) { return r.ToString();}
...
}
OK, I use the MyTable as a binding source for a DataGridView. I can load the data grid easily using InitFromString on individual fields in MyStruct.
The problem comes when I try to edit a value in a cell of the DataGridView. Going to the first row, first column, I change the value of the existing number. It gives an exception blizzard, the first line of which says:
System.FormatException: Invalid cast from 'System.String' to 'MyReal'
I've looked at the casting discussions and reference books but don't see any obvious problems.
Any ideas?
I tried your method of handling CellParsing, and it worked. Although I did it a little differently, handling any types:
private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
e.Value = Activator.CreateInstance(e.DesiredType, new object[] { e.Value });
e.ParsingApplied = true;
}
The DataGridView uses a TypeConverter.
You must define a TypeConverter object for your structure and decorate it with the TypeConverterAttribute, so that the DataGridView uses it as soon as it encounters a property that is typed with your structure.
The example I give here of such a TypeConverter is a bit rudimentary, but the Degree structure I use is similar to yours, it will give you a good idea of what to do.
[TypeConverter(typeof(DegreeConverter))]
public struct Degree {
double Value;
public Degree(double v) { Value = v; }
public static implicit operator double(Degree v) => v.Value;
public static implicit operator Degree(double v) => new Degree(v);
public override string ToString() => Value.ToString();
}
class DegreeConverter : TypeConverter {
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
return sourceType == typeof(string) ? true : base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
return destinationType == typeof(string) ? true : base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
return new Degree(Convert.ToDouble(value));
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
return value.ToString();
}
}
I (almost) fixed this problem by handling the CellParsing event, e.g.
private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
... // (checking goes here)
e.Value = new MyReal(e.Value.ToString());
e.ParsingApplied = true;
}
e.Value is being set correctly but the DataGridView still shows the old value. How does the new value get placed in the BindingList?
Do I need an explicit method call to force the new value into the BindingList and, if so, where?
My gridcells are filled with objects of type GridValueGroup and they have an ObjValue property displayed by the ToString override. When modifying the string in the grid cell, the CellParsing event is handled by:
filling the cell-value and
modifying the e.Value (which is of type string initially while the DesiredType is GridValueGroup) to become the desired type.
This way I avoid creating a new object because the cell already has that object.
Also it keeps the entered value in the data source. Not certain yet if it blocks other events (CellValueChanged has to be handled sometimes after the parsing of the value).
private void grid_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
string val = e.Value.ToString();
DataGridViewCell cell = this.dgvGroup1[e.ColumnIndex, e.RowIndex];
if (e.DesiredType == typeof(GridValueGroup))
{
((GridValueGroup)cell.Value).ObjValue = val;
e.Value = ((GridValueGroup)cell.Value);
}
e.ParsingApplied = true;
}
So I have the following snippet of code:
private Nullable<decimal> _excessWages;
public decimal ExcessWages
{
get
{
return _excessWages ?? CalculateExcessWages();
}
set
{
if (value != CalculateExcessWages())
_excessWages = value;
else
_excessWages = null;
}
}
So basically the behavior I'm trying to implement is if a field is left blank or is assigned a value equal the calculated one use the calculated value, otherwise store the assigned value.
I have a lot of fields that need to support overriding like this. Is this the best way to accomplish this? If not what would you suggest?
I worked on this a bit based mostly on Vlad's suggestion. Turns out you can use a single generic class to abstract this. Here is the end result:
public class Overridable<T>
{
private Func<T> _calculate;
private readonly Func<T, T, bool> _compare;
protected T _t;
public Overridable(Func<T> calculate, Func<T, T, bool> compare)
{
_calculate = calculate;
_compare = compare;
}
public T Value
{
get { return _compare(_t, default(T)) ? _calculate() : _t; }
set { _t = _compare(value, _calculate()) ? default(T) : value; }
}
}
You need to pass in a compare delegate because the type isn't known until you set it in a subclass. So a simple == isn't going to cut it. I went the easy route and used a Func delegate but this could be replaced with a normal delegate if it had to be adapted for .NET 2.0 for some reason.
You'll notice I'm using default(T) instead of null. This works because the default value for a Nullable<T> is null (or more precisely, undefined but it works out to be the same).
This doesn't prevent you from trying to declare an Overridable<T> for a non-nullable type. What you'd wind up with won't through run time errors but it isn't as useful. Trying to set a Overridable<decimal>.Value to null will get you a compiler error. While setting it to default(decimal) will cause it to revert to calculating the value.
I went this route because the properties from this the class I'm using this in needs to populate a serializable object thats eventually transmitted as xml. The schema for the xml includes numeric fields defined as a mixture of integers, decimals and strings.
You then use the Overriddable class like so:
private Overridable<decimal?> _excessWages =
new Overridable<decimal?>(CalculateExcessWages, (x,y) => x == y);
public virtual decimal? ExcessWages
{
get
{
return _excessWages.Value;
}
set
{
_excessWages.Value = value;
}
}
The only problem I ran into with this was that CalculateExcessWages is a non-static method so it can't be used in a field initializer. Since all the properties in my class are non-static I had to initialize all the backing fields in the constructor.
You can make a class wrapper for this.
class OverridableValue<T>
{
public OverridableValue<T>(Func<T> calculator)
{
_calculator = calculator;
}
private Nullable<T> _t;
private Func<T> _calculator;
public T Get()
{
return return _t ?? _calculator();
}
public void Set(T value)
{
_t = (value != _calculator()) ? value : null;
}
}
It's not so syntactically sweet, but at least saves some keystrokes.
Now you can use it like this:
class Foo
{
OverridableValue<decimal> _excessWages =
new OverridableValue<decimal>(CalculateExcessWages);
public decimal ExcessWages
{
get { return _excessWages.Get(); }
set { _excessWages.Set(value); }
}
...
}
The advantage is that the whole logic is hidden at the class.
You could do this by defining a handy set/get helper method
private static T GetUtil<T>(ref Nullable<T> value, Func<T> calc) {
return value ?? calc();
}
private static void SetUtil<T>(ref Nullable<T> value, T newValue, Func<T> calc) {
if ( newValue != calc() ) {
value = newValue
} else {
value = null;
}
}
private Nullable<decimal> _excessWages;
public decimal ExcessWages
{
get { return GetUtil(ref _excessWages, CalculateExcessWages); }
set { SetUtil(ref _excessWages, value CalculateExcessWages); }
}
That looks reasonable to my eyes. The only change I might make is to cache CalculateExcessWages(), if it is expensive to do, and ok to cache:
private Nullable<decimal> _excessWages;
private Nullable<decimal> _excessWagesCalculated;
public virtual decimal ExcessWages
{
get
{
if (_excessWagesCalculated == null)
_excessWagesCalculated = CalculateExcessWages();
return _excessWages ?? _excessWagesCalculated;
}
set
{
if (_excessWagesCalculated == null)
_excessWagesCalculated = CalculateExcessWages();
if (value != _excessWagesCalculated)
_excessWages = value;
else
_excessWages = null;
}
}
But, this is more code than yours, and I think you are looking to simplify.