Get runtime getter of interface property - c#

Declarations:
interface I
{
int i { get; set; }
}
class C : I
{
public int i { get; set; }
}
Code:
C c = new C();
c.i = 10;
PropertyInfo pi1 =
c.
GetType().
GetInterfaces().
SelectMany(t => t.GetProperties()).
ToArray()[0];
PropertyInfo pi2 =
c.
GetType().
GetProperties()[0];
object v1 = pi1.GetValue(c);
object v2 = pi2.GetValue(c);
Hey, v1 == v2, pi1 != pi2, but GetValue obviously calls same method. How can I know in my code that pi1 and pi2 call same method body?

You can use Type.GetInterfaceMap() to get a mapping between interface members and the implementing members for a specific type. Here's an example:
using System;
using System.Linq;
using System.Threading;
interface I
{
int Value { get; set; }
}
class C : I
{
public int Value { get; set; }
}
public class Test
{
static void Main()
{
var interfaceGetter = typeof(I).GetProperty("Value").GetMethod;
var classGetter = typeof(C).GetProperty("Value").GetMethod;
var interfaceMapping = typeof(C).GetInterfaceMap(typeof(I));
var interfaceMethods = interfaceMapping.InterfaceMethods;
var targetMethods = interfaceMapping.TargetMethods;
for (int i = 0; i < interfaceMethods.Length; i++)
{
if (interfaceMethods[i] == interfaceGetter)
{
var targetMethod = targetMethods[i];
Console.WriteLine($"Implementation is classGetter? {targetMethod == classGetter}");
}
}
}
}
That prints Implementation is classGetter? True - but if you change the code so that fetching I.Value doesn't call C.Value, e.g. by adding a base class so that C.Value is a new property, not an implementation of I.Value:
interface I
{
int Value { get; set; }
}
class Foo : I
{
public int Value { get; set; }
}
class C : Foo
{
public int Value { get; set; }
}
... then it will print Implementation is classGetter? False.

Related

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.

Dynamic cast in c# in runtime

I have 2 classes as you can see :
static void Main(string[] args)
{
object m = (??????)"salam";
}
public class A
{
public string name { set; get; }
public static implicit operator A(string _name)
{
A aa = new A();
aa.name = _name;
return aa;
}
}
public class B
{
public string family { set; get; }
public static implicit operator B(string _family)
{
B bb = new B();
bb.family = _family;
return bb;
}
}
I need to cast my string in runtime in this line :
object m = (??????)"salam";
Is there any solution to pass my class name as a string to cast my value .for example in runtime I need to cast "salam" to A or maybe B
The static cast is working good like this
object m = (A)salam";
object m = (B)"salam";
But I need to cast my string in runtime
Type x=null;
If(condition)
x can be type of A
else
x can be type of B
object m = (x)"salam";
You need to use Interfaces for such a need. The following code shows how to do so.
To simulate your situtation, I wrote a method to return either A or B based on time.
Here the list contains a bunch of objects which may be of Type A or B, depending on the second of execution. In the real-world scenario, you would get your types in various other ways.
public class StackOverflowQuestion
{
public static void Run()
{
List<IBase> list = new List<IBase>();
string types = "";
for (int i = 0; i < 10; i++)
{
var randomType = GiveMeARandomIBaseType();
System.Threading.Thread.Sleep(750);
IBase hello = randomType.Convert("salam");
list.Add(hello);
types += hello.GetType().Name + ",";
}
types = types.Trim(',');
//sample result : B,B,A,B,A,A,B,A,B,B
}
static IBase GiveMeARandomIBaseType() {
if (DateTime.Now.Second % 2 == 0)
return new A();
else
return new B();
}
}
public interface IBase {
public IBase Convert(string s);
}
public static class MyExtensions {
public static T Convert<T>(this string str, IBase b) where T : IBase {
try
{
return (T)b.Convert(str);
}
catch (Exception)
{
return default;
}
}
}
public class A : IBase
{
public IBase Convert(string s) {
return (A)s;
}
public string name { set; get; }
public static implicit operator A(string _name)
{
A aa = new A();
aa.name = _name;
return aa;
}
}
public class B : IBase
{
public IBase Convert(string s)
{
return (B)s;
}
public string family { set; get; }
public static implicit operator B(string _family)
{
B bb = new B();
bb.family = _family;
return bb;
}
}
I had a similar problem and after all the study and time, I was able to approach the desired result in the following way.
I used an internal method to access (the inside of) the class and this method returns the cast desired result.
Step 1: in class
public class A
{
public string Name { set; get; }
public static implicit operator A(string name)
{
return new A
{
Name = name
};
}
public A GetCasting(object a)
{
A i = (A)a;
return i;
}
}
public class B
{
public string Family { set; get; }
public static implicit operator B(string family)
{
return new B
{
Family = family
};
}
public B GetCasting(object b)
{
B i = (B)b;
return i;
}
}
Step 2: in controller or code
var className = "A";
var classMethod = "GetCasting";
var classType = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsClass && t.Name == className).FirstOrDefault();
var classInstance = Activator.CreateInstance(classType);
var castMethod = classType.GetMethod(classMethod);
var yourObject = "salam";
var objectData = new object[] { yourObject };
var resultObject = castMethod.Invoke(classInstance, objectData);

How to check if an object has default values in 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.

NUnit's CollectionAssert return false for similar lists of custom class

Here is my class:
public class MyClass
{
public string Name { get; set; }
public string FaminlyName { get; set; }
public int Phone { get; set; }
}
Then I have two similar list:
List<MyClass> list1 = new List<MyClass>()
{
new MyClass() {FaminlyName = "Smith", Name = "Arya", Phone = 0123},
new MyClass() {FaminlyName = "Jahani", Name = "Shad", Phone = 0123}
};
List<MyClass> list2 = new List<MyClass>()
{
new MyClass() {FaminlyName = "Smith", Name = "Arya", Phone = 0123},
new MyClass() {FaminlyName = "Jahani", Name = "Shad", Phone = 0123}
};
The problem is that NUnit CollectionAssert return false always.
CollectionAssert.AreEqual(list1,list2);
Am I missing something about CollectionAssert test
The AreEqual checks for equality of the objects. Since you did not override the Equals method, it will return false in case the references are not equal.
You can solve this by overriding the Equals method of your MyClass:
public class MyClass {
public string Name { get; set; }
public string FaminlyName { get; set; }
public int Phone { get; set; }
public override bool Equals (object obj) {
MyClass mobj = obj as MyClass;
return mobj != null && Object.Equals(this.Name,mobj.Name) && Object.Equals(this.FaminlyName,mobj.FaminlyName) && Object.Equals(this.Phone,mobj.Phone);
}
}
You furthermore better override the GetHashCode method as well:
public class MyClass {
public string Name { get; set; }
public string FaminlyName { get; set; }
public int Phone { get; set; }
public override bool Equals (object obj) {
MyClass mobj = obj as MyClass;
return mobj != null && Object.Equals(this.Name,mobj.Name) && Object.Equals(this.FaminlyName,mobj.FaminlyName) && Object.Equals(this.Phone,mobj.Phone);
}
public override int GetHashCode () {
int hc = 0x00;
hc ^= (this.Name != null) ? this.Name.GetHashCode() : 0;
hc ^= (this.FaminlyName != null) ? this.FaminlyName.GetHashCode() : 0;
hc ^= this.Phone.GetHashCode();
return hc;
}
}

Is there a more elegant way to sum multiple properties?

I have a class which contains multiple properties of type Int32:
public class MyClass
{
public int C1 { get; set; }
public int C2 { get; set; }
public int C3 { get; set; }
.
.
.
public int Cn { get; set; }
}
I want to sum all this properties. Instead of doing:
int sum = C1 + C2 + C3 + ... + Cn
is there a more efficient/elegant method?
You can fake it, but I'm not sure how useful it is:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
var test = new MyClass();
// ...
int sum = test.All().Sum();
}
}
public class MyClass
{
public int C1 { get; set; }
public int C2 { get; set; }
public int C3 { get; set; }
// ...
public int Cn { get; set; }
public IEnumerable<int> All()
{
yield return C1;
yield return C2;
yield return C3;
// ...
yield return Cn;
}
}
}
If you really want to perform the sum without having to type each property you can use reflection to iterate through your properties but this is involves a big performance cost. However, for fun you can do something like this:
var item = new MyClass();
// Populate the values somehow
var result = item.GetType().GetProperties()
.Where(pi => pi.PropertyType == typeof(Int32))
.Select(pi => Convert.ToInt32(pi.GetValue(item, null)))
.Sum();
PS: Don't forget to add using System.Reflection; directive.
Maybe you can use an array or a data structure which has the IEnumarable interfaces vs a custom class. Then you can use linq to do Sum().
If there's a strong enough need to store the values in separate members (properties, fields), then yes, that's the only way. If you have a list of numbers however, store them in a list, not in separate members.
Or, ugly:
new[]{C1,C2,C3,C4}.Sum()
But more characters than the single "+" anyway.
public class MyClass
{
readonly int[] _cs = new int[n];
public int[] Cs { get { return _cs; } }
public int C1 { get { return Cs[0]; } set { Cs[0] = value; } }
public int C2 { get { return Cs[1]; } set { Cs[1] = value; } }
public int C3 { get { return Cs[2]; } set { Cs[2] = value; } }
.
.
.
public int Cn { get { return Cs[n-1]; } set { Cs[n-1] = value; } }
}
Now you can use Enumerable.Sum with MyClass.Cs, and you can still map C1, C2, ... to database fields.

Categories

Resources