How Upcasting preserve derived classes's Properties? [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
static void Main(string[] args)
{
Student student = new Student()
{
ID = 12,
Name = "Manu",
LastName = "Shekar"
};
Iregister x = student;
Student newstudent = x as Student;
//Console.WriteLine(x.LastName); //Uncommenting this shows compilation error
Console.WriteLine(newstudent.LastName); //This Show "Shekar"
Console.ReadKey();
}
class Student : Iregister
{
public int ID { get; set; }
public string Name { get; set; }
public String LastName { get; set; }
}
interface Iregister
{
int ID { get; set; }
String Name { get; set; }
}
I wonder how the newstudent.LastName gets the correct value since it is casted from Iregister which doesn't have LastName property?
How the value "Shekar" is passed from student.LastName to newstudent.LastName. Did x stores it somewhere in between? Pardon me if i miss something basics.

You create a single object, and assign a reference to it in the variable student.
You then create a second reference to the same object and assign that to x. Both x and student are referring to the same object, but the type of the x variable means that only the members defined on IRegister are available.
You then create a third reference to the same object and assign that to newstudent. Since newstudent is of type Student, you can access all of the member of Student from that reference.
Not that the variables just store references. It's the object that stores its own actual data, and that object remained unchanged throughout the process.

I wonder how the newstudent.LastName gets the correct value since it
is casted from Iregister which doesn't have LastName property?
The truth is that x is a type Iregister but it's pointing to a Student object hence once casted you're able to access the Student fields.

When using x directly, the compiler allows you to choose only the members defined on IRegister type, because x is of that type. Once you cast x to Student, the compiler allows you to use any member of Student, since the newstudent variable is of type Student.

How Interface stores inherited class's Property
Interfaces do not store values. They only ensure the availability of certain properties and methods in the classes that implement the interface.
I wonder how the newstudent.LastName gets the correct value since it is casted from Iregister which doesn't have LastName property?
Downcasting an object does not change the object's type, it only changes the type of the variable that you're using.
public interface IMyInterface
{
String Name { get; }
}
public class BaseType : IMyInterface
{
public virtual String Name
{
get { return "Base Name"; }
}
}
public class DerivedType : BaseType
{
public override String Name
{
get { return "Derived Name"; }
}
}
I then tested the following commands in the C# Interactive window:
var derived = new DerivedType();
IMyInterface derivedAsInterface = derived;
BaseType derivedAsBaseType = derived;
derived.Name //returns "Derived Name"
derivedAsInterface.Name //returns "Derived Name"
derivedAsBaseType.Name //returns "Derived Name"
As you can see, whenever you ask for the Name property, the object still behaves as a DerivedType, because that is what the object is.
This is because classes are inherently reference types. This does work differently for value types (e.g. float and int), but that has to do with the inherent differences between value and reference types.
If you want to know why, read up on the difference between value and reference types in C#
If you think about it, your assumption does not make sense. In my code example, I have three separate variables: derived, derivedAsInterface, derivedAsBaseType. These all point to the same object in memory.
This logically means that the same object must be compatible with all three variables, otherwise it would be impossible to use all these variables when you want to.
If the object was changed into an object of type IMyInterface, then my variables derivedAsBaseType and derived would no longer function correctly.
If the object was changed into an object of type BaseType, then my variable derived would no longer function correctly.
The only remaining explanation is that my object has always kept its original type (DerivedType), since that is the only way how it can maintain compatibility with all three variables.
If you do not understand why they refer to the same object in memory, you should read up on the difference between value and reference types in C#. This topic is much too broad for an answer on StackOverflow.

Related

c# type of an object when using derived class

Having the following code:
class TrxBase
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
class Trx : TrxBase
{
public string Prop3 { get; set; }
}
static void Print(TrxBase trx)
{
if (trx is Trx trx1)
{
Console.WriteLine(trx1.Prop3);
}
else
{
Console.WriteLine("no match");
}
}
static void Main(string[] args)
{
Trx t = new Trx();
t.Prop1 = "prop 1";
t.Prop3 = "prop 3";
Print(t);
}
The code from above prints "prop 3". From what I knew. in the Print method, the object will be read as an TrxBase one. And if this is the case, where is the Prop3 property saved? How does the program knows that my parameter is actually an Trx object?
You need to distinguish between compile time types (those that e.g. determine which overload of a method to call) and runtime types (which are used by e.g. reflection). Whatever contortions you go through with a particular object1 (casting it to a base type, etc) doesn't change the runtime type of the object.
So just because you're passing t to Print which asks for a TrxBase, it doesn't change t into a TrxBase.
And if, inside Print, it tests for and determines that it's a Trx, it's perfectly valid for it to cast it back to that type (hidden inside the pattern matching syntax) and start treating it as the type it truly is (although, of course, it could be a type even more derived from Trx.
Bonus reading: Eric Lippert's Representation and Identity
1Provided you understand that reference-changing conversions give you a new object. This is also further explained in the bonus reading above.
This is how C# works, when you pass derived type object to a method with parameter with base type object compiler simply takes this derived object and interprets it like it is base.
In your case you are passing derived (Trx) object to method with TrxBase parameter. So now in the scope of Print(TrxBase trx) , trx will be treated like it is TrxBase, but then you are using pattern matching to determine if this trx can be reprsented into more derived Trx object type, which in your case is true, can and therefore prints prop 3.
It is possible to cast derived type to more base type, but the other way will result into InvalidCastException coming from CLR. Because if you think about it - lets say you allocate new object of type TrxBase, CLR allocator will allocate such object on the heap (or the stack if value type) with all the needed properties this object has. Now if you request from CLR to cast this specific object to something more specific you are ultimately requesting this specific memory layout to change into another (adding fields, properties and such from your specific object) which CLR does not support.

Why an object saves properties when upcasted

I've got a simple question concerning upcasting in c#. For example I have two interfaces:
interface IUSer
{
string UserName { get; set; }
}
interface IAdmin: IUSer
{
string Password { get; set; }
}
...and a class implementing IAdmin interface:
class Admin : IAdmin
{
public string Password { get; set; }
public string UserName { get; set; }
}
When I create an object of type Admin and try to upcast it to IUser, technically I can then only access UserName user.UserName:
var admin = new Admin() { UserName = "Arthur", Password = "hello" };
var user = (IUSer)admin;
Console.WriteLine( user.UserName );
...but If I cycle through this object's properties using Reflection, like that:
private static void Outputter(IUSer user)
{
foreach (var prop in user.GetType().GetProperties())
{
Console.WriteLine(prop.Name + " " + prop.GetValue(admin));
}
}
...I can also see Password property. The question is - why it is saved when upcasted?
The question is - why it is saved when upcasted?
Because casting doesn't change the object at all. It just changes how you're viewing the object.
Think of it like being a person. You may have different ways that people can view you:
A colleague
A manager
A family member
A friend
They only "see" certain aspects of you, but that doesn't change who you are.
Likewise a simple reference conversion doesn't change the object. If you call user.GetType() it will still report the actual type of the object. It's just that when you view the object through a particular lens (whether that's an interface or a base class) you only see the members that lens shows you.
(Note that a cast that calls a user-defined conversion, e.g. casting from XElement to string, is entirely different. That returns a reference to a new object, rather than just regarding the existing object in a different way.)
If you only want to see the IUser properties, use typeof(IUser).GetProperties() instead of calling GetType() first:
private static void Outputter(IUser user)
{
foreach (var prop in typeof(IUser).GetProperties())
{
Console.WriteLine($"{prop.Name}: {prop.GetValue(user)}");
}
}
Although I'm not sure it's particularly useful to do that with reflection in most cases.
when you cast the object of any type to their base type, you are just holding that object with they type of base.
object doesn't loos its properties by that.
If you see a simplest example : Use of non generic collection
when you add some object (let's say of Admin class) in ArrayList, you are actually converting that object into type object (Boxing) and then store it arraylist. So it is ultimate example of up-casting! How?
The object type is an alias for Object in the .NET Framework. In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from Object.
Full Post
Now object type doesn't hold properties like userName password.
So when you try to access those property from the object you get directly from arraylist, you will not able to do so. Because current you are dealing with the type object and you will get access only those properties or members which is supported by object type (but here you are not getting access, still those properties are there). In addition as note in other answer GetType() method will surely return it's original type too.
But when you get that original object back from array list by casting it back to Admin type (Unboxing) , you will see those properties are there in your object as they were before. Only thing which is changed is, now you are able to access them because Admin type supports them.
Read this for more detail

How to prevent Json.NET from using use default values for missing constructor parameters while still using default values for properties? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Is there a way to tell JSON.net that when it attempts to deserialize using a constructor (if there is no default constructor), that it should NOT assign default value to constructor parameters and that it should only call a constructor if every constructor parameter is represented in the JSON string? This same serializer SHOULD use default values when calling property/field setters, the rule is only scoped to constructors. None of the enum values here seem to be appropriate: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_DefaultValueHandling.htm
The solution should NOT rely on applying any attributes to the types being deserialized.
for example, the json string "{}" will deserialize to an object of type Dog by setting the Dog's age to 0 (the default value for an int). I'd like to a generalized, not-attribute-based solution to prevent this from happening. In this case, {"age":4} would work because age is specified in the JSON string and corresponds to the constructor parameter.
public class Dog
{
public Dog(int age)
{
this.Age = age;
}
public int Age { get; }
}
However, if Dog is specified as such, then "{}" should deserialize to a Dog with Age == 0, because the Dog is not being created using a constructor.
public class Dog
{
public int Age { get; set; }
}
As to "why would you want to do this"... Objects with constructors are typically qualitatively different than POCOs as it relates to their properties. Using a constructor to store property values instead of settable properties on a POCO typically means that you want to validate/constrain the property values. So it's reasonable not to allow deserialization with default values in the presence of constructor(s).
When Json.NET encounters an object without a parameterless constructor but with a parameterized constructor, it will call that constructor to create the object, matching the JSON property names to the constructor arguments by name using reflection via a case-insensitive best match algorithm. I.e. a property whose name also appears in the constructor will be set via the constructor call, not the set method (even if there is one).
Thus, you can mark a constructor argument as required by marking the equivalent property as required:
public class Dog
{
public Dog(int age)
{
this.Age = age;
}
[JsonProperty(Required = Required.Always)]
public int Age { get; }
}
Now JsonConvert.DeserializeObject<Dog>(jsonString) will throw when the "age" property is missing.
Since this is something you always want, you can create a custom contract resolver inheriting from DefaultContractResolver or CamelCasePropertyNamesContractResolver that marks properties passed to the constructor as required automatically, without the need for attributes:
public class ConstructorParametersRequiredContractResolver : DefaultContractResolver
{
protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo)
{
var property = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);
if (property != null && matchingMemberProperty != null)
{
var required = matchingMemberProperty.Required;
// If the member is already explicitly marked with some Required attribute, don't override it.
// In Json.NET 12.0.2 and later you can use matchingMemberProperty.IsRequiredSpecified to check to see if Required is explicitly specified.
// if (!matchingMemberProperty.IsRequiredSpecified)
if (required == Required.Default)
{
if (matchingMemberProperty.PropertyType != null && (matchingMemberProperty.PropertyType.IsValueType && Nullable.GetUnderlyingType(matchingMemberProperty.PropertyType) == null))
{
required = Required.Always;
}
else
{
required = Required.AllowNull;
}
// It turns out to be necessary to mark the original matchingMemberProperty as required.
property.Required = matchingMemberProperty.Required = required;
}
}
return property;
}
}
Then construct an instance of the resolver:
static IContractResolver requiredResolver = new ConstructorParametersRequiredContractResolver();
And use it as follows:
var settings = new JsonSerializerSettings { ContractResolver = requiredResolver };
JsonConvert.DeserializeObject<T>(jsonString, settings)
Now deserialization will throw if the "age" property is missing from the JSON.
Notes:
This only works if there is a corresponding property. There doesn't appear to be a straightforward way to mark a constructor parameter with no corresponding property as required.
Newtonsoft recommends that you cache and reuse the contract resolver for best performance.
Demo fiddle here.

Is "where T : class" not enforced in any way at compile time or run time?

In the following code, I pass a struct into a constructor that is expecting a class. Why does this compile and run without error (and produce the desired output)?
class Program
{
static void Main()
{
var entity = new Foo { Id = 3 };
var t = new Test<IEntity>(entity); // why doesn't this fail?
Console.WriteLine(t.Entity.Id.ToString());
Console.ReadKey();
}
}
public class Test<TEntity> where TEntity : class
{
public TEntity Entity { get; set; }
public Test(TEntity entity)
{
Entity = entity;
}
public void ClearEntity()
{
Entity = null;
}
}
public struct Foo : IEntity
{
public int Id { get; set; }
}
public interface IEntity
{
int Id { get; set; }
}
If I change my Main() method so that it includes a call to ClearEntity(), as shown below, it still generates no error. Why?
static void Main()
{
var entity = new Foo { Id = 3 };
var t = new Test<IEntity>(entity);
Console.WriteLine(t.Entity.Id.ToString());
t.ClearEntity(); // why doesn't this fail?
Console.ReadKey();
}
where TEntity : class forces TEntity to be a reference type, but an interface such as IEntity is a reference type.
See here:
http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx
where T : class | The type argument must be a reference type, including any class, interface, delegate, or array type
Regarding your second question, you might think t.ClearEntity() would fail because it's assigning null to a variable whose type is a value type, but that's not the case. The compile-time type of Entity is the reference type IEntity, and the runtime type (after assignment) is the null type. So you never have a variable of type Foo but value null.
from the C# documentation:
where T : class
The type argument must be a reference type, including any class, interface, delegate, or array type. (See note below.)
Because you're passing the struct via an interface, it's still considered a reference type.
Within the .net runtime, every non-nullable value type has an associated reference type (often referred to as a "boxed value type") which derives from System.ValueType. Saying Object Foo = 5; won't actually store an Int32 into Foo; instead it will create a new instance of the reference type associated with Int32 and store a reference to that instance. A class constraint on a generic type specifies that the type in question must be some sort of a reference type, but does not by itself exclude the possibility that the type may be used to pass a reference to a boxed value-type instance. In most contexts outside generic type constraints, interface types are regarded as class types.
It's important to note that not only are boxed value types stored like reference types; they behave like reference types. For example, List<string>.Enumerator is a value type which implements IEnumerator<string>. If one has two variables of type List<string>.Enumerator, copying one to the other will copy the state of the enumeration, such that there will be two separate and independent enumerators which point to the same list. Copying one of those variables to a variable of type IEnumerator<string> will create a new instance of the boxed value type associated with List<string.Enumerator and store in the latter variable a reference to that new object (which will be a third independent enumerator). Copying that variable to another of type IEnumerator<string>, however, will simply store a reference to the existing object (since IEnumerator<string> is a reference type).
The C# language tries to pretend that value types derive from Object, but within the guts of the .net Runtime they really don't. Instead, they're convertible to types which derive from System.ValueType (which in turn derives from Object). The latter types will satisfy a type constraint, even though the former ones will not. Incidentally, despite its name, System.ValueType is actually a class type.
I, likewise, assumed that constraint keyword class meant the same class as the type declaration keyword class, but it doesn't.
As explained in the other answers, the term class here is over-loaded, which seems to me to be a horrible decision for the C# language design. Something like referencetype would have been more helpful.

Detecting if class property is a reference type

Is it possible when looking at a class' properties to detect if any of them is a reference type.
Take below as an example:
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProgrammeClient
{
public int Id { get; set; }
public bool IsActive { get; set; }
public IClient Client { get; set; }
}
ProgrammeClient: -
Id and IsActive are properties but Client is a reference type. Is there a way of detecting this?
Many thanks,
Kohan.
Addendum
The reason i ask is: I am using a mapper that checks types are the same before matching property names and copying the values. My hope is to detect classes and override the type matching and simply copy the classes properties if the THEY type match.
Well, it sounds like you may be trying to detect the difference between a value type and a reference type. You can find that out using Type.IsValueType... but be aware that value types can easily have properties too. (Think about DateTime for example.) Also, some types which you may want to regard as "not objects" are reference types - string being a prime example.
Another option would be to use Type.IsPrimitive - is that what you're looking for? If so, you should be aware that decimal, DateTime and string are not primitive types.
If you can describe exactly what makes a type an "object" in your way of thinking (or rather, in whatever way makes a semantic difference in what you're trying to do with your type). I suspect you don't currently have a very clear set of criteria - coming up with those criteria may well clarify other aspects of your current task, too.
You can use a little reflection to see if a property is a value type or a class type. Class is probably what you mean by "object". All types in .NET derive from the object type.
Client.GetType().IsClass
Or you can loop through all properties and see which are compound
foreach(var p in ProgrammeClient.GetType().GetProperties())
{
if(p.PropertyType.IsClass) Console.WriteLine("Found a class");
}
Check if the type is a string and check if it is a class.
public static bool IsNonStringClass(this Type type)
{
if (type == null || type == typeof(string))
return false;
return typeof(Type).IsClass;
}
All properties in your example return objects, as everything is an object in .NET; int and bool are objects. If you mean a reference type, as opposed to value types, then you can do the following:
foreach (PropertyInfo pi in typeof(Client).GetProperties()) {
if (pi.PropertyType.IsClass) {
// reference type
// DoMyFunkyStuff
}
}
You can enumerate the properties via Reflection, and check them:
bool ContainsOnlyValues() {
return typeof(ProgrammeClient).GetProperties().All(x => x.PropertyType.IsValueType);
}
The Type.IsvalueType property can reveal this.
Id.GetType().IsValueType
This will be True for Id, false for a class
If using TypeSupport nuget package you can simply do:
typeof(ProgrammeClient).GetExtendedType().IsReferenceType;
TypeSupport does inspection and provides deeper insight on the capabilities of a given type, handling things like strings, enums etc and makes it easier to code these types of things.

Categories

Resources