Is there a way to qualify property names when using object initializers? - c#

Background: a class constructor can have parameters whose names are the same as its properties, and resolve the assignment using the this keyword. Simplified example:
public MyClass(string Thing1, string Thing2)
{
this.Thing1 = Thing1;
this.Thing2 = Thing2;
}
What about object initializers? I want to instantiate an object, setting properties Amount and Percentage from parameters of the same name passed to the current method.
How can I qualify Amount and Percentage to distinguish the object properties from the method parameters?

I guess you're not using object initializer, instead you just have the braces with parameter assigned to itself.. With object initializers, it just works.
Here is the minimal repro:
private static void Dosomething(string Name)
{
{ Name = Name };//Assignment made to same variable error
var test = new TestClass{ Name = Name };//Works fine
}
class TestClass
{
public string Name { get; set; }
}

Related

Best Way to Retrieve Actual Concrete Object Of a Certain Type From a Json-String in C#?

I'm currently struggling with determining which types a json-string deserializer gives back in C#. I've tried to make a base TypeWHATEVER class where TypeX and TypeY inherited from them, but still whenever I try to retrieve the actual object with that specific type, it doesn't work since both can create a new instance with the same constructor.
Let's say I have TypeX and TypeY. They both have similar constructors, for example: both have a constructor with parameters (string a, string b). However, TypeY has an additional constructor with parameters, for example (string a, string b, string c).
Now whenever I use the additional constructor or even just the similar constructor in TypeY, it still doesn't produce the results I want (It still sees it as TypeX as well as TypeY)...
In one of the methods I don't know which type to return, because the object is being deserialized from a Json-String. Also putting T and on the method that gives the object backs works, but it works for both classes which isn't what I want... I even put a enum in each different underlying Type classes, but that didn't work since the Type is defined in the base class as well.
How or what is the best way to determine how to get the actual object type from a json string where there are similar constructors, but still they differ from each other...
Please help me through this :(
Below you'll find sample code of what I'm trying to achieve..
Like I said earlier I have a base class or interface doesn't matter and two child classes
Base Class: E.g. Parent.cs
public class Parent
{
public virtual ClassType Type { get; protected set; } = ClassType.Undefined;//this is an enum and used to differentiate between the different classes. However, this doesn't work, because of the parent type will always be Undefined whenever a child type is converted from json-string to explicit Parent type...
public string Id { get; set; }
public string Message { get; set; }
public Parent()
{
}
public Parent(string id, string message = "")
{
Id = id;
Message = message;
}
}
Child Class: E.g. ChildA.cs
public class ChildA : Parent
{
public override ClassType Type => ClassType.Default;
public ChildA()
{
}
public ChildA(string id, string message = "") : base(id, message)
{
}
}
Child Class: E.g. ChildB.cs
public class ChildB : Parent
{
private object testObjectA;
private object testObjectB;
private object testObjectC;
public override ClassType Type => ClassType.New;
public object TestObjectA
{
get { return testObjectA; }
set { testObjectA = value; }
}
public object TestObjectB
{
get { return testObjectB; }
set { testObjectB = value; }
}
public object TestObjectC
{
get { return testObjectC; }
set { testObjectC = value; }
}
public ChildB()
{
}
public ChildB(string id, string message) : base(id, message)
{
}
public ChildB(string id, IDictionary<string, object> collection, string message = "") : this(id, message) // should I use 'this' or 'base' here for id and message, because I already get the base class for the second constructor and it makes sense to me just to take this class since the other is already been using the base class?
{
testObjectA = collection[Constants.A];
testObjectB = collection[Constants.B];
testObjectC = collection[Constants.C];
}
}
Json Converter Class: E.g. JsonConverterClass.cs
public static T StringToObject<T>(string json)
=> JsonConvert.DeserializeObject<T>(json);//using Newtonsoft.Json;
Now I have a Json-String that I want to convert to either a ChildA or ChildB. The Json-String is something like this:
{
"type": "New",//This is the ClassType for example
"id": "Some String...",
"message": "",
"collection": {
"objectA": "A",
"objectB": "B",
"objectC": "C",
}
}
Let's try to convert the Json-string which won't work and give that Child object back in a method, unfortunate this doesn't work:
public Parent GetObjectExample(string json_String)
{
Parent parentClass = JsonConverterClass.StringToObject<Parent>(json_String);// I don't know how I maybe can use reflection here to accomplish, maybe this is an option too?
switch (parentClass.Type)
{
case ClassType.Default:
parentClass = parentClass as ChildA;
break;
case ClassType.New:
parentClass = parentClass as ChildB;
break;
}
return parentClass;
}
The problem here is that I expect ChildB to given back. However, since both classes have the same constructor. It doesn't recognizes to give ChildB back. In fact, it just gives a random class back.. Either ChildA or ChilB and in most cases it just gives ChildA back what's really weird.
Hopefully, I could be clear as possible to inform you about what is going on and I really don't know why my approach doesn't work...
Ok, I think there are many things to comment. Let's begin:
In your constructor with 3 parameters, use this instead of base. Imagine this situation:
public ChildB(string id, string message)
: base(id, message)
{
this.FullName = $"{id} {message}";
}
public ChildB(string id, IDictionary<string, object> collection, string message = "")
: this(id, message)
{
}
Calling this, your 3 params constructor run the 2 params constructor setting the FullName property. If you use base, FullName won't be initialized and you must duplicate this line in your 3 params constructor.
C# know the type of any object. Really, you don't need your ClassType property. You can do things like:
if (myChildBInstance.GetType() == typeof(ChildB))
I recomend you remove this property.
Also, that property is protected. You can't change it's value from serialization. Serialization (by default) works with public properties.
The key in your question, I think, is with the constructors. When you serialize, you use always the parameterless constructor. In the deserialization, constructor without parameters is invoked and later, the properties are setted.
Your Type property in the JSON string is never used. You can't set the value because is protected and your instance is created before you start processing these properties.
var json = #"{
'type': 'New',//This is the ClassType for example
'id': 'Some String...',
'message': '',
'collection': {
'objectA': 'A',
'objectB': 'B',
'objectC': 'C',
}
}";
var obj = StringToObject<ChildB>(json);
When you run the previous code, a ChildB object is created (because T type of StringToObject) and then, all the JSON string (public) properties are setted. So it's impossible that your type property may be useful to choose the type of the object. collection is not a property of your object: this is the reason why your object don't get these A,B,C values.
With this sample:
var childB = new ChildB
{
Id = "Id",
Message = "Msg",
TestObjectA = 1,
TestObjectB = 2,
TestObjectC = 3
};
var json = JsonConvert.SerializeObject(childB);
Your JSON must be like this:
{
"TestObjectA":1,
"TestObjectB":2,
"TestObjectC":3,
"Id":"Id",
"Message":"Msg"
}
And then, you get your valid object in this way:
var obj = StringToObject<ChildB>(json);
If you are going to work with distinct types and inheritance, then you must use the TypeNameHandling = TypeNameHandling.All that I commented before i my link https://stackoverflow.com/a/72270480/18452174.

Default values without default constructor

How do the data members of the type get their default values when the default constructor is omitted and if they're given default values anyways what is the use of the default constructor in the first place ?
class Program
{
static void Main(string[] args)
{
Person person = new Person("SomeName");
Console.WriteLine(person.Age);
Console.WriteLine(person.FamileName == null);
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string FamileName { get; set; }
public Person(string name)
{
Name = name;
}
}
Edit:
This is from a book I've been reading and it's what got me thinking that the default constructor is responsible for giving the data members their default values but it seems that I got it wrong and it's only a way for me to modify these values if I needed to, please correct me if I'm wrong.
Every C# class is provided with a “freebie” default constructor that you can redefine if need be. By definition,
a default constructor never takes arguments. After allocating the new object into memory, the default
constructor ensures that all field data of the class is set to an appropriate default value
Object fields are always initialized with default values if you won't specify differently using constructor or field initialization (same goes for properties).
Default value usualy corresponds to all bits set to zero (null for reference types, 0 for numeric types).
You can set other value using constructor:
public Person()
{
Name = "Sebastian";
}
or initializer:
public string Name { get; set; } = "Sebastian";
In C# you can assign default value.
class Person
{
public string Name { get; set; } ="Someone";
public int Age { get; set; }
public string FamileName { get; set; }
}
If you want to assign the values in the initialization of object you can do this:
class Program
{
static void Main(string[] args)
{
Person person = new Person { Name= "SomeOne"; Age=16; };
Console.WriteLine(person.Age);
Console.WriteLine(person.FamileName == null);
}
}
If you only need to assign values or default value, you do not need the constructor. You can do it in the above mention methods.
I normally use constructors when I need to do some additional tasks e.g. database connection, setting up other object and etc.
Link: https://msdn.microsoft.com/en-us/library/bb397680.aspx
The members in your class will be initialized with their default values. For reference types, this is null and for value types, it's the default value. There's nothing special about being members in an object - it's the same values they would have if they were in the middle of a function:
public void Foo()
{
string name; // null
int age; // 0
bool isChild; // false
}
As for the default constructor, it's a nice place to make sure your data types are safe. For example, you might want to initialize any reference typed properites to a non-null value:
class Widget
{
public string Name { get; set; }
public Widget()
{
Name = string.Empty; // this way someone can call Widget.Name safely
}
}
On a related note, you should also see: How do you give a C# Auto-Property a default value?

Get the original property name from a method parameter

How can I get the name of the original property name which is passed as a parameter to a method?
class TestA
{
public string Foo { get; set; }
public TestA()
{
Foo = "Bar";
TestB.RegisterString(Foo);
}
}
class TestB
{
public static void RegisterString(string inputString)
{
// Here I want to receive the property name that was used
// to assign the parameter input string
// I want to get the property name "Foo"
}
}
You can add an argument with the nameof keyword. Not sure why you would want that anyway:
TestB.RegisterString(Foo, nameof(Foo));
This will pass in "Foo" as the second argument. There is no way to automate this, so you don't need to call nameof yourself, which makes doing this quite useless.
If you would call this from the Foo property, you could use the CallerMemberNameAttribute, which will put in the caller's name. The compiler will set the correct value, so you don't have to supply this yourself in the calling method.
public static void RegisterString( string inputString
, [CallerMemberName] string caller = null
)
{
// use caller here
}
That makes more sense to me.

No parameterless constructor defined for this object when trying to retrieve my object C#

I have this method that I want to use to return an Object that i have created by passing in the type name:
public object GetObjectType(object objectTypeName)
{
Type objecType = objectTypeName.GetType();
return Activator.CreateInstance(objecType);
}
When I do this:
var a = GetObjectType("Person");
I get: No parameterless constructor defined for this object.
Im not too sure what this CreateInstance does so im flying blind here.
Do I need to add something to my class which looks like this:
public class Person
{
public string Name {get; set;}
}
In fact you are trying to create new instance of String type, which indeed does not have a parameterless contructor.
public object GetObjectType(object objectTypeName)
{
Type objecType = objectTypeName.GetType(); // objecType is String here
return Activator.CreateInstance(objecType); // creation of String fails
}
What you might really want to do is this:
public object GetObjectType(string objectTypeName)
{
Type objecType = Type.GetType(objectTypeName);
return Activator.CreateInstance(objecType);
}
Try to add a parameterless constructor:
public class Person
{
public string Name {get; set;}
public Person() {} // Parameterless constructor
}
It seems that your are trying to create object without passing arguments to available parameterised constructor u have. Try this:
public object GetObjectType(object objectTypeName)
{
Type objecType = objectTypeName.GetType();
//ur code works fine if do not have parameterised constructor
return Activator.CreateInstance(objecType,"(do not forget to pass arguments)");
}
Here is how I have solved the problem:
Type objectType = Type.GetType("MyProject.Models.Person", true);
Object objectTypeInstance = (Activator.CreateInstance(objectType));
I can now retrieve my objects

What's the return type of an anonymous class

I have a class that used to have a string return type. Now I find I need to return more than a string. I was thinking to return something like below:
public string Test()
{
return ( new { ID = 5, Name= "Dave" } );
}
Is this even possible and if so then what would be the return type? I know it's not string ..
As others have said, the best thing to do here is to make a nominal type. I would suggest that the nominal type have the same characteristics as an anonymous type; that is, you should consider making the type immutable and consider making it exhibit value equality.
It is possible to return an anonymous type as object and then use the instance returned elsewhere using a variety of sneaky techniques. You can cast the object to "dynamic" (in C# 4) and then use the properties of the anonymous type, but this is slow and lacks compile-time type checking.
You can also use the "cast by example" trick, which does get you compile-time type checking. However, that trick only works when the anonymous source object and the anonymous example object come from the same assembly.
static T CastByExample<T>(object source, T example) where T : class
{
return source as T;
}
static object ReturnsAnonymous() { return new { X = 123 }; }
static void DoIt()
{
object obj = ReturnsAnonymous();
var example = new { X = 0 };
var anon = CastByExample(obj, example);
Console.WriteLine(anon.X); // 123
}
See how sneaky that is? We use method type inference and local variable type inference to tell the compiler "these two things are the same type". This lets you export an anonymous type as object and cast it back to anonymous type.
But you probably should not do this; if you're resorting to such sneaky tricks then you should simply be defining a nominal type in the first place. Also, like I said, the trick only works if the example and the source objects were created in code in the same assembly; two "identical" anonymous types in two different assemblies do not unify to be the same type.
The object that you return does have a class, but it's anonymous so you can't specify it in the code. You just have to return it as an object reference:
public object Test() {
return new { ID = 5, Name= "Dave" };
}
Note that the anonymous type is unknown outside the scope of the method, so reflection is the only way to access its properties.
If you want to be able to use the returned object conveniently, you should declare a class:
public class TestResult
{
public int ID { get; set; }
public string Name { get; set; }
}
public TestResult Test() {
return new TestResult() { ID = 5, Name= "Dave" };
}
Another alternative is to use an existing class, if it fits your purpose. A KeyValuePair is close to what you use, but then the properties will of course be named Key and Value instead of ID and Name:
public KeyValuePair<int, string> Test() {
return new KeyValuePair<int, string>(5, "Dave");
}
This isn't possible as the anonymous class is only valid within the current context. If you need to return an object then you'll need to create a real class.
I'm assuming you left string as the return type by accident.
Anonymous type are class type that are derived directly from object.
You can return it from method as object as return type.
Have a look at this.
No, it's not possible. Your options are:
Define a real class for the return value,
Use System.Tuple, or
Use out parameters (probably the least good option).
You can make a struct (or class) for this.
public struct IdAndName
{
public int Id;
public string Name;
public IdAndName(int id, string name)
{
ID = id;
Name = name;
}
}
You could also use a Tuple<T1, T2>, (but that's not recommended as the properties aren't named.
class NewString
{
public int ID { get; set; }
public string Name { get; set; }
}
public NewString Test()
{
return ( new NewString() { ID = 5, Name = "Dave" } );
}
:)

Categories