How to check if an object has default values in C# - c#

I have an object that I want to check whether it contains default values or not, in the below code but that doesn't cut it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
MyClass obj1 = new MyClass();
MyClass obj2 = null;
if(obj1 == new MyClass())
Console.WriteLine("Initialized");
if(Object.ReferenceEquals(obj1, new MyClass()))
Console.WriteLine("Initialized");
}
}
}
public class MyClass
{
public int Value {get; set; }
public MyClass()
{
this.Value = 10;
}
}
I have also used Object.ReferenceEquals() but that doesn't cut it as well.
This is the fiddle I am working on.
Is there a way to check whether an object contains default values, or if the object is empty?
Edit: In case of an newly initialized object with many nested properties, how to check whether they contain a default value or not?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
MyClass obj1 = new MyClass();
MyClass obj2 = null;
if(obj1 == new MyClass())
Console.WriteLine("Initialized");
if(Object.ReferenceEquals(obj1, new MyClass()))
Console.WriteLine("Initialized");
}
}
}
public class MyClass
{
public int Value {get; set; }
public MyNestedClass MyProperty { get; set; }
public MyClass()
{
this.Value = 10;
this.MyProperty = new MyNestedClass();
}
}
public class MyNestedClass
{
public string SomeStringProperty { get; set; }
public MyNestedClass()
{
this.SomeStringProperty = "Some string";
}
}
Here is the fiddle in the case of nested objects.

You can achieve your goal by overriding Equals and GetHashCode, creating and saving an immutable "default" instance, and comparing the value to it:
public class MyClass {
public static readonly MyClass DefaultInstance = new MyClass();
public int Value { get; set; }
public MyClass() {
this.Value = 10;
}
public override int GetHashCode() {
return Value.GetHashCode();
}
public override bool Equals(Object obj) {
if (obj == this) return true;
var other = obj as MyClass;
return other?.Value == this.Value;
}
}
Now you can check if the instance is equal to a newly created one by calling
if (MyClass.DefaultInstance.Equals(instanceToCheck)) {
... // All defaults
}
You can change what it means for an instance to be "default" by altering DefaultInstance object.
Note: this trick works well only with immutable MyClass. Otherwise some code could perform MyClass.DefaultInstance.Value = 20 and change the "default" object.

Here is one method using JSON serialization that allows you to check if the objects are equal or not:
DotNetFiddle:
using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var defaultObj = new MasterObject();
var notDefaultObject = new MasterObject();
var defaultJson = JsonConvert.SerializeObject(defaultObj);
var notDefaultJson = JsonConvert.SerializeObject(notDefaultObject);
Console.WriteLine("First Test");
if (defaultJson == notDefaultJson)
Console.WriteLine("Same thing");
else
Console.WriteLine("Not same thing");
notDefaultObject.Sub1.SomeObject.SomeOtherValue = "Not a default Value";
notDefaultJson = JsonConvert.SerializeObject(notDefaultObject);
Console.WriteLine("Second Test");
if (defaultJson == notDefaultJson)
Console.WriteLine("Same thing");
else
Console.WriteLine("Not same thing");
}
}
public class MasterObject
{
public SubObject1 Sub1 { get; set; }
public SubObject2 Sub2 { get; set; }
public string SomeString { get; set; }
public MasterObject()
{
Sub1 = new SubObject1();
Sub2 = new SubObject2();
SomeString = "Some Default String";
}
}
public class SubObject1
{
public string SomeValue { get; set; }
public SubObject2 SomeObject { get; set; }
public SubObject1()
{
SomeObject = new SubObject2();
SomeValue = "Some other Default String";
}
}
public class SubObject2
{
public string SomeOtherValue { get; set; }
public SubObject2()
{
SomeOtherValue = "Some default";
}
}
Output:
First Test
Same thing
Second Test
Not same thing
What is happening is that you serialize the default object and then you make changes to the "not default object", re-serialize and compare again. This can be slow because you are generating strings, but as long as all the sub-objects can be serialized this will be the simplest way to compare if an object is "default" (what you get from new) or has been modified.

Related

Reflection - How to copy common properties from one class to another when there are subclasses

I'm working on a c# application and trying to make this code working. It fails when it tries to copy a property which is a list of a subclass object.
I'm able to check the common properties in both classes and the code works fine for most types I've used, even List<string>. When I have properties of type e.g. List<SubClass>it fails. The code fails also for simple objects of the Subclass.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Questions
{
class Program
{
static void Main(string[] args)
{
Class1 class1 = new Class1
{
Prop1 = "X",
List1 = new List<Class1.SubClass>
{
new Class1.SubClass { SubProp1 = "A", SubProp2 = "B" }
}
};
Class2 class2 = class1.CopyTo<Class2>(); //---> fails when it tries to SetValue for the List<SubClass>
}
}
public class Class1
{
public string Prop1 { get; set; }
public List<SubClass> List1 { get; set; }
public string Prop3 { get; set; }
public class SubClass
{
public string SubProp1 { get; set; }
public string SubProp2 { get; set; }
}
}
public class Class2
{
public string Prop1 { get; set; }
public List<SubClass> List1 { get; set; }
public string Prop4 { get; set; }
public class SubClass
{
public string SubProp1 { get; set; }
public string SubProp2 { get; set; }
}
}
public static class Extensions
{
public static T CopyTo<T>(this Object sourceObject)
{
Type sourceObjectType = sourceObject.GetType();
Type targetType = typeof(T);
var targetInstance = Activator.CreateInstance(targetType, false);
List<PropertyInfo> identicalProperties = new List<PropertyInfo>();
var propertiesTarget = typeof(T).GetProperties();
var propertiesSource = sourceObject.GetType().GetProperties();
foreach (var s_property in propertiesSource)
{
foreach (var t_property in propertiesTarget)
{
if (s_property.Name.Equals(t_property.Name))
{
identicalProperties.Add(s_property);
continue;
}
}
}
object value;
foreach (PropertyInfo property in propertiesTarget)
{
var res = identicalProperties.Any(x=>x.Name.Equals(property.Name));
if (!res)
{
continue;
}
value = sourceObjectType.GetProperty(property.Name).GetValue(sourceObject, null);
property.SetValue(targetInstance, value, null);
}
return (T)targetInstance;
}
}
}
I assume this is achievable but I'm struggling to find a way to identify the type of property and when to cast the value to the correct type here property.SetValue(targetInstance, value, null);. value should probably be casted as a List.
The error thrown by the compiler is:
System.ArgumentException: 'Object of type 'System.Collections.Generic.List1[Questions.Class1+SubClass]' cannot be converted to type 'System.Collections.Generic.List1[Questions.Class2+SubClass]'
Can anyone help? Much appreciated.
In absence of further details or comments I would just like to feedback the final solution I'm adopting. Basically, the use of a outside defined class (instead an internal defined class) will allow the code to work but and provides a practical example how it can work based on this assumption. This is an workaround rather than the solution for my original question.
The example final code as follows:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Questions
{
class Program
{
static void Main(string[] args)
{
Class1 class1 = new Class1
{
Prop1 = "X",
Prop2 = "Y",
List1 = new List<OutsideClass>
{
new OutsideClass { SubProp1 = "A", SubProp2 = "B" },
new OutsideClass { SubProp1 = "C", SubProp2 = "D" },
new OutsideClass { SubProp1 = "E", SubProp2 = "F" }
}
};
Class2 class2 = class1.CopyTo<Class2>();
}
}
public class Class1
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public List<OutsideClass> List1 { get; set; }
public string Prop3 { get; set; }
}
public class Class2
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public List<OutsideClass> List1 { get; set; }
public string Prop4 { get; set; }
}
public class OutsideClass
{
public string SubProp1 { get; set; }
public string SubProp2 { get; set; }
public override string ToString()
{
string text = string.Format("{0} ---> {1}", SubProp1, SubProp2);
return text;
}
}
public static class Extensions
{
public static T CopyTo<T>(this Object sourceObject)
{
Type sourceObjectType = sourceObject.GetType();
Type targetType = typeof(T);
var targetInstance = Activator.CreateInstance(targetType, false);
List<PropertyInfo> identicalProperties = new List<PropertyInfo>();
var propertiesTarget = typeof(T).GetProperties();
var propertiesSource = sourceObject.GetType().GetProperties();
foreach (var s_property in propertiesSource)
{
foreach (var t_property in propertiesTarget)
{
if (s_property.Name.Equals(t_property.Name))
{
identicalProperties.Add(s_property);
continue;
}
}
}
object value;
foreach (PropertyInfo property in propertiesTarget)
{
var res = identicalProperties.Any(x=>x.Name.Equals(property.Name));
if (!res)
{
continue;
}
value = sourceObjectType.GetProperty(property.Name).GetValue(sourceObject, null);
property.SetValue(targetInstance, value, null);
}
return (T)targetInstance;
}
}
}
All common properties will be copied from one class to the other (Prop3 and Prop4 will be disregarded as they only exist in each one of these classes).
I hope this can help anyone trying to do the same.
Please feel free to comment back and provide further details.
Thanks a lot for everyone comments.
Happy new year!

StackOverflowException when deserializing json for self referencing class instances

I have a class that contains Range[] as property and Range class is a self referencing class. I used [JsonIgnore] to prevent StackoverflowException but it works for only Serialize not Deserialize. How can I fix this?
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace testoverflow
{
class Program
{
public static void Main(string[] args)
{
GlobalVariable.Json = "[{\"TotalBytesReceived\":0,\"Id\":\"b03750fb291a46708f8e1a7409553075\",\"NofThread\":8,\"Speed\":0,\"Progress\":0.0,\"FilePath\":\"C:\\\\Users\\\\kafeinaltor\\\\Downloads\",\"RangeDir\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\",\"Url\":\"http://ipv4.download.thinkbroadband.com/20MB.zip\",\"Ranges\":[{\"Start\":0,\"End\":9223372036854775806,\"TotalBytesReceived\":0,\"IsDownloaded\":false,\"FileId\":\"87cd7715dc0740c1b82ddd681bf2523d\",\"Size\":9223372036854775807,\"Status\":4,\"IsIdle\":false,\"SaveDir\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\",\"FilePath\":\"C:\\\\Users\\\\kafeinaltor\\\\AppData\\\\Roaming\\\\87cd7715dc0740c1b82ddd681bf2523d\",\"Md5Checksum\":null}],\"Info\":null,\"DownloadRequestMessage\":null}]";
var a = new MTDO();
Console.WriteLine(GlobalVariable.Json);
Console.ReadKey(true);
}
public static class GlobalVariable
{
public static string Json { get; set; }
}
public class MTDO
{
public MTDO()
{
Ranges = new Range[]
{
new Range(0L, 100L, ""),
new Range(101L, 200L, "")
};
Id = Guid.NewGuid().ToString("N");
Reminder.AddOrUpdate(this);
}
public string Id { get; set; }
public Range[] Ranges{ get; set; }
}
public class Range
{
public long Start { get; set; }
public long End { get; set; }
public string SaveDir { get; set; }
public long TotalBytesReceived{ get; set; }
public Range(long start, long end, string saveDir)
{
this.Start = start;
this.End = end;
this.SaveDir = Guid.NewGuid().ToString();
}
[JsonIgnore]
public Range Remaining
{
get
{
return new Range(Start + TotalBytesReceived, End, SaveDir);
}
}
}
public class Reminder
{
public Reminder()
{
}
public static void AddOrUpdate(MTDO mtdo)
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
var exists = list.Any(x => x.Id == mtdo.Id);
if (!exists)
list.Add(mtdo);
else
{
var i = list.Select((x, j) => new {val = x, index = j})
.First(x => x.val.Id == mtdo.Id).index;
list[i] = mtdo;
}
WriteJson(list);
}
public static List<MTDO> ReadList()
{
var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
if (list == null)
list = new List<MTDO>();
return list;
}
static string Read()
{
try
{
return GlobalVariable.Json;
}
catch
{
return "";
}
}
static void WriteJson(List<MTDO> list)
{
GlobalVariable.Json = JsonConvert.SerializeObject(list);
}
}
}
}
UPDATE: I have updated myquestion adding minimum reproducable code in Console Application. You can copy/paste and run directly.
The problem is that you have an infinite recursion:
You call MTDO constructor
Inside MTDO constructor you call Reminder.AddOrUpdate(this);
Inside that method you have var list = JsonConvert.DeserializeObject<List<MTDO>>(Read());
Which calls MTDO constructor again (step 1)
These steps keep repeating until you get StackOverflowException.

Correctly create a class with subclasses (C#)

I am creating a program in C# and I don't know how to create my classes.
Here's what my class looks like:
public class MyClass
{
public class Parameters
{
string Value { get; set;}
}
public class Methods
{
public void MyMethod()
{
Window.Title = Parameters.Value;
}
}
}
And this is how I want to be able to use it from another class:
public class MainClass
{
MyClass myclass = new MyClass();
myclass.Parameters.Value = "Hello World !";
myclass.Methods.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass();
myclass2.Parameters.Value = "Hello World Again !";
myclass2.Methods.MyMethod();
//I know this code is stupid, it's just to simplify my example.
}
But it doesn't work, there are accessibility problems that I don't know how to solve.
Thanks in advance, I don't think that the solution is very complicated but I can't find it.
You need to make the Value property public to get or set it from outside the class:
public string Value { get; set; }
The classes are not static, so you need to instantiate them to set their properties or use their methods:
var parameters = new MyClass.Parameters();
parameters.Value = "Hello World !";
var methods = new MyClass.Methods();
methods.MyMethod();
The same applies here:
public void MyMethod()
{
var parameters = new MyClass.Parameters();
Window.Title = parameters.Value;
}
But I suspect you actually want MyClass to have its own instances of these classes. So you can add properties for them:
public Properties Properties { get; set; }
public Methods Methods { get; set; }
Then instantiate them somehow (like in the constructor):
public MyClass()
{
Parameters = new Parameters();
Methods = new Methods();
}
If you do steps 1, 4 and 5, the code you have in MainClass should work.
Create a constructor that force the user to add a Value when initiating the class
public class MyClass
{
public string Value { get; set; }
public MyClass(string value)
{
Value = value;
}
public class Methods
{
public void MyMethod()
{
Window.Title = Value;
}
}
}
and call it like this
MyClass myclass = new MyClass("Hello World !");
myclass.Methods.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass("Hello World Again !");
myclass2.Methods.MyMethod();
You can declare the properties and methods all within the class:
public class MyClass
{
public MyClass()
{
// Set any initial values
}
public string Value { get; set;}
public void MyMethod()
{
Window.Title = Value;
}
}
And then to use it:
public class MainClass
{
MyClass myclass = new MyClass();
myclass.Value = "Hello World !";
myclass.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass();
myclass2.Value = "Hello World Again !";
myclass2.MyMethod();
}
Or to be more succinct:
public class MainClass
{
MyClass myclass = new MyClass {
Value = "Hello World !"
};
myclass.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass {
Value = "Hello World Again !"
};
myclass2.MyMethod();
}
UPDATE
If you absolutely need the classes split (although I wouldn't recommend it), then you need to pass your value into the method class to use it. There are a couple of approaches. Either you have to pass the value down into you methods class (not a very elegant approach):
public class MyClass
{
public string Value { get; set;}
public Methods methods {get; set;)
public MyClass(string value)
{
methods = new Methods(value);
Value = value;
}
public class Methods
{
public string Value { get; set;}
public Methods(string value)
{
Value=value;
}
public void MyMethod()
{
Window.Title = Value;
}
}
}
Or make MyMethod() a static method and pass in the value to use:
public class MyClass
{
public string Value { get; set;}
public MyClass(string value)
{
methods = new Methods(value);
Value = value;
}
}
public static class Methods
{
public static void MyMethod(string Value)
{
Window.Title = Value;
}
}
public class MainClass
{
MyClass myclass = new MyClass {
Value = "Hello World !"
};
Methods.MyMethod(myclass.Value);
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass {
Value = "Hello World Again !"
};
Methods.MyMethod(myclass2.Value);
}
Both ways are not best practice though as, when you start building more complex classes, having the properties and methods in different places will cause a load of headaches.

Mocking adding items to a list in .NET NMock2

I'm using NMock2 (2.1.3641.27570) in my unit tests.
IList<MyObj> values = _mock.NewMock<IList<MyObj>>();
That mock I return when my tested object calls the Values get property on my mocked object:
Expect.AtLeastOnce.On(_myKeepMock).GetProperty("Values").Will(Return.Value(values));
Then I expect value which is a MyObj to be added to my list values:
Expect.AtLeastOnce.On(values).Method("Add").With(value);
In order to avoid unexpected invocation of list'1.Add upon execution I understand I have to override the Equals method in the MyObj class:
public override bool Equals(object obj) { ...}
and compare by value instead of reference. But it doesn't even get called when executing the test (breakpoint not hit).
What do I need to do in order to pass the test when the item added to the list in the call is equal in value to the one added by the tested object?
I read about custom matchers but not sure if those apply here.
UPDATE
Full example:
using System.Collections.Generic;
using System.Linq;
using NMock2;
using NUnit.Framework;
public class Data
{
public int Val { get; set; }
public Data(int val) { Val = val; }
}
public class ModData
{
public int Val { get; set; }
protected bool Equals(ModData other)
{
return this.Val.Equals(other.Val);
}
public override int GetHashCode()
{
return this.Val.GetHashCode();
}
public override bool Equals(object obj)
{
ModData m = (ModData)obj;
return m != null && this.Val == m.Val;
}
}
public interface IAllData
{
IList<Data> Data { get; set; }
IList<ModData> ModData { get; set; }
}
public class AllData : IAllData
{
public IList<Data> Data { get; set; }
public IList<ModData> ModData { get; set; }
}
public class Calco
{
private IAllData _allData;
public Calco(IAllData allData)
{
_allData = allData;
}
public void Sum()
{
_allData.ModData.Add(new ModData { Val = _allData.Data.Sum(d => d.Val) });
}
}
public class CalcoTest
{
[Test]
public void Test()
{
Mockery mockery = new Mockery();
IList<Data> data = new List<Data>();
IList<ModData> modData = mockery.NewMock<IList<ModData>>();
IAllData allData = mockery.NewMock<IAllData>();
ModData modDatum = new ModData { Val = 4 };
data.Add(new Data(1));
data.Add(new Data(10));
Calco c = new Calco(allData);
Expect.AtLeastOnce.On(allData).GetProperty("Data").Will(Return.Value(data));
Expect.AtLeastOnce.On(allData).GetProperty("ModData").Will(Return.Value(modData));
Expect.AtLeastOnce.On(modData).Method("Add").With(modDatum);
c.Sum();
mockery.VerifyAllExpectationsHaveBeenMet();
}
}
Output:
NMock2.Internal.ExpectationException : unexpected invocation of list`1.Add(<WRM.Common.RiskCalculation.Tests.ModData>)
Expected:
at least 1 time: allData.Data, will return <System.Collections.Generic.List`1[WRM.Common.RiskCalculation.Tests.Data]> [called 1 time]
at least 1 time: allData.ModData, will return <list`1> [called 1 time]
at least 1 time: list`1.Add(equal to <WRM.Common.RiskCalculation.Tests.ModData>) [called 0 times]
Notice how it expects invocation of list'1.Add(<WRM.Common.RiskCalculation.Tests.ModData>)
and then shows it didn't call list'1.Add(<WRM.Common.RiskCalculation.Tests.ModData>)
Custom Matchers ARE the answer: http://nmock.sourceforge.net/advanced.html
public class IsMod
{
public static Matcher Equal(ModData otherMod)
{
return new ModMatcher(otherMod);
}
}
internal class ModMatcher : Matcher
{
private readonly ModData _mod;
public ModMatcher(ModData mod)
{
_mod = mod;
}
public override bool Matches(object o)
{
ModData m = (ModData)o;
return _mod.Val.Equals(m.Val);
}
public override void DescribeTo(TextWriter writer)
{
writer.Write("Value same ");
writer.Write(_mod.Val);
}
}
And then
Expect.AtLeastOnce.On(modData).Method("Add").With(IsMod.Equal(modDatum));
Done!

instance access to class members of inherited abstract

This is theory Thursday I guess.
Shouldn't Main() have access to _XLocal & _YLocal?
using System;
namespace HelloGoodbyeOperator {
public abstract class HGOperator {
public string _greeting { get; set; }
public bool _x { get; internal set; }
public bool _y { get; internal set; }
public static implicit operator HGOperator(bool mode) {
object ret = new object();
if (mode)
ret = new HGOperator_Hello { _greeting = "hello", _XLocal = 10 };
else
ret = new HGOperator_Goodbye { _greeting = "goodbye", _YLocal = 20 };
return (HGOperator)ret;
}
}
public class HGOperator_Hello : HGOperator {
public int _XLocal { get; set; }
public HGOperator_Hello() { _x = true; Console.WriteLine("HGOperator_Hello //" + _XLocal.ToString() + "\\\\"); }
}
public class HGOperator_Goodbye : HGOperator {
public int _YLocal { get; set; }
public HGOperator_Goodbye() { _y = false; Console.WriteLine("HGOperator_Goodbye //", _YLocal, "\\\\"); }
}
class Program {
static void Main(string[] args) {
HGOperator hg = true;
Console.WriteLine(hg._greeting);
test(hg);
Console.WriteLine("");
hg = false;
Console.WriteLine(hg._greeting);
test(hg);
Console.ReadKey();
}
static void test(HGOperator hg) {
if (hg is HGOperator_Hello) {
Console.WriteLine(hg._x);
//Console.WriteLine(hg._XLocal);
} else {
Console.WriteLine(hg._y);
//Console.WriteLine(hg._YLocal);
}
}
}
}
Here is the output
HGOperator_Hello //0\
hello
True
HGOperator_Goodbye //
goodbye
False
I can understand how trying to access hg._YLocal of a HGOperator_Hello type would be a nightmare & vise-versa. But would still think I could get to the respective members with caution.
Also and I will bet this is realted. The two concrete constructors do not have a value for _XLocal & _YLocal on the Console.Writeline()s. Without the .ToString() just a "" is printed. Why not?
Thanks.
The issue is that the compiler doesn't know that hg is a derived type of HGOperator_Hello or HGOperator_Goodbye. So inside your if you need to create another variable and cast it:
if (hg is HGOperator_Hello)
{
var helloHg = (HGOperator_Hello)hg;
Console.WriteLine(helloHg._x);
Console.WriteLine(helloHg._XLocal);
}
else
{
var goodbyeHg = (HGOperator_Goodbye)hg;
Console.WriteLine(goodbyeHg._y);
Console.WriteLine(goodbyeHg._YLocal);
}

Categories

Resources