I was reading This Article over on Jag Reeghal's blog and It seemed to me that what he was suggesting was really not the same thing as using an object initializer. Then I realized that I didn't really know for sure.
When an object is constructed, with object initializers, and one of those intitializers throws (maybe a Null Reference exception)... is the object actually constructed? Is this basically like an exception being thrown in the constructor? Or is the object fully constructed, and then initialized?
An object initilizer statement like var x = new Foo { Property1 = 5}; will be implemented as something like this:
Foo temp = new Foo();
temp.Property1 = 5;
x = temp;
As you can see, the properties in the initiallizer are set after the object is constructed, however the variable isn't set to the fully-initialized object until all the properties are set, so if an exception is thrown, the constructed object is lost even if the exception is caught (the variable will remain null or whatever value it had before).
It is fully constructed first, then initialized. You will however never get a reference to such an object if an exception is thrown, the compiler makes sure that your reference can only ever refer to a properly initialized object. It uses a temporary to guarantee this.
So for example, this code:
var obj = new Model {
FirstName = reader[0].ToString(),
LastName = reader[1].ToString(),
Age = Convert.ToInt32(reader[2].ToString())
};
Is rewritten by the compiler to:
var temp = new Model();
temp.FirstName = reader[0].ToString();
temp.LastName = reader[1].ToString();
temp.Age = Convert.ToInt32(reader[2].ToString())
var obj = temp;
The object would be constructed, but the initialization would not complete. Initialization is just a compiler trick; look at the generated IL and you'll see its the same either way. The blog post is complaining that its harder to tell what line the exception occurred on, but personally I've never had that difficultly.
You all need to be aware the the compiled IL is NOT always the same!!
The difference is in Debug/Release build configurations.
Have a look in reflector if you dont believe me .....
Related
How can I access the objects property in this situation?
Araba araba = new Araba();
araba.Renk = "mavi";
araba.fiyat = 12345;
// I created this class and it working normally
ArrayTypedStack asd = new ArrayTypedStack(10);
asd.Push(araba);
object araba2 = asd.Pop();
araba2. //cant access
Here you are assigning the value of asd.Pop() to a variable of the type object.
object is the root of all objects (all objects inherit from it and can be casted to it) and as such has no real information about what it is. It's just like any object in real life is a thing.
The solution here is to declare the araba2 as the type Araba, that will give you access to all the properties on the next line.
I don't know the implementation of the ArrayTypedStack and what the Pop() method looks like (it's return type) so it's possible that this will give you an error, saying that it can't convert an object to the type Araba. This is the type safety implemented in .NET. You have to convince .NET that it's of the type Araba, this can be by casting
Araba araba2 = (Araba)asd.Pop();
this can still give an error on runtime if the object returned from Pop() isn't of the type Araba, in this case you can ask .NET to try to cast it, there are serveral options for this:
object popResult = asd.Pop();
if (popResult is Araba) {
Araba araba2 = (Araba)popResult;
}
// can be written as follows:
if (popResult is Araba araba3) {
araba3.fiyat = 65432;
}
// can also be done as follows
Araba araba4 = asd.Pop() as Araba;
if (araba4 != null) {
araba4.fiyat = 84368;
}
Well, your araba2 variable is of type object. Thus, regardless of the actual type of the instance it contains, through the object variable araba2 you can only access members that are provided by the type object.
To access members provided by the Araba type (and assuming the instance in the araba2 variable is an instance of type Araba), the araba2 variable itself should be of type Araba, or the value of araba2 needs to be cast as Araba.
Thus,
var araba2 = asd.Pop();
or
var araba2 = (Araba) asd.Pop();
with the first example code line above requiring that the return type of the Pop method is Araba (or a type derived from Araba). The latter code line example will work regardless of the return type of Pop as long as the value returned by Pop is an actual Araba instance (or is something that is convertible to an Araba instance).
I'm writing a compare properties two objects of some class, for further listing differences.
Class oldObj, newObj;
//some initiation of above
Class classObject = new Class();
var objectKeys = classObject .GetType().GetProperties().ToList();
objectKeys.ForEach(key => {
var previousKeyValue = key.GetValue(oldObj);
var newKeyValue = key.GetValue(newObj);
if (!Equals) {...}
});
In special cases, newObj or oldObj can be nulls.
My problem is that, in such a case: key.GetValue(null) I'm getting CS0120 exception - "Non-static method requires a target".
Looking at PropertyInfo options (from metadata):
public object? GetValue(object? obj);
I assumed that it will be able to handle such a situation with object being null, with e.g. return null as its value.
Could you please explain if this is proper behaviour of this code, or I'm making something wrong to use null?
In such a case I would probably just before ForEach make some verification if objects are nulls and write separate compare code, handling this situation.
You are misunderstanding the nature of the parameter that is passed to GetValue().
When you pass in an object reference, it means that the reference is an instance property on an instance of an object. If you omit the object reference, you are telling the reflection api that you are trying to access a static member.
I have an object with 100 properties. Is there a feature in Resharper or Visual Studio 2017 that generates the code for all the properties of the object. e.g.
var myObject = new ObjectWithMultipleProps
{
Prop1 = "",
Prop2 = 0,
Prop3 = "",
...etch
}
I am creating unit tests and it would speed up things if this would be possible.
type this much:
var myObject = new ObjectWithMultipleProps {
Then press Ctrl+J, Tab. The next unused field or Property will get auto completed for you. You can press Ctrl+J again and it will pop up the type of the field so you can choose an appropriate value. Or you can start typing new then press Ctrl+J and it will auto-complete the type for you.
Then type a comma, and repeat the process for each field. Fields that you have already specified will not appear in the list. If you do not want to set a value for a field, then omit it from the initializer list, and it will get its default value.
You seem to have a misunderstanding on what creating an instance means. There´s no way for an instantiated object (this is when you called new ...) to have no value for any of your members. All those members are initialized from the runtime to the default-type for the type of that member. In particular you can´t partly initialize your object, that is set only some members to an initial-value, whilst not setting others. Creating an instance is an all-or-nothing-operation.
So if you simply write this:
var myObject = new ObjectWithMultipleProps();
all properties within myObject will have their defualt-value. You can even print them:
Console.WriteLine(myObject.Prop2); // this will print 0
You coul of course write all those assignments into the class´ constructor:
class ObjectWithMultipleProps
{
public ObjectWithMultipleProps()
{
Prop1 = null;
Prop2 = 0;
}
}
This however has the exact same effect.
What may happen anyway is, that you get a NullReferenceException. This is because all reference-types default to null, making any call to those members yield to that exception, as shown in the following code:
var a = myObject.Prop1.SubsString(0, 1);
As Prop1 is initialized to null once the instance is completely created, you get a NullReferenceException, because you can´t call any member on null.
If you want other default-values for your members, you have to create the constructor and set the values there.
Please see the code below:
var MyViewModel = new MyViewModel();
var MyDomainModel = AutoMapper.Map<MyDomainModel>(MyViewModel);
MyDomainModel = service.DoSomething(MyDomainModel);
The MyDomainModel reference is overwritten with the return type from: service.DoSomething();
Should I be passing MyDomainModel by reference in this case or does it not really make much difference?
I am looking at a lot of code that was written like the above and I am wandering if there is a reason for it that I am not aware of.
If, as the comments indicate, DoSomething just modifies properties of the object passed in but returns the same object then you could replace
MyDomainModel = service.DoSomething(MyDomainModel);
with
service.DoSomething(MyDomainModel);
It doesn't matter because either way MyDomainModel will still refer to the same object.
We have two possible cases here.
The Original Instance is Modified
public MyDomainModel DoSomething(MyDomainModel model)
{
model.Property1 = X;
model.Property2 = Y;
return model;
}
Then you have to pass the original instance as argument but you can transform your function into a void since classes are passed by reference:
public void DoSomething(MyDomainModel model)
{
model.Property1 = X;
model.Property2 = Y;
}
var MyViewModel = new MyViewModel();
var MyDomainModel = AutoMapper.Map<MyDomainModel>(MyViewModel);
service.DoSomething(MyDomainModel);
// MyDomainModel.Property1 is set to X now...
The Original Instance is Replaced
public MyDomainModel DoSomething(MyDomainModel model)
{
// ...
return (new MyDomainModel());
}
In this case, if the method doesn't make any use of model, you can basically avoid passing it as argument:
public MyDomainModel DoSomething()
{
// ...
return (new MyDomainModel());
}
var MyViewModel = new MyViewModel();
var MyDomainModel = AutoMapper.Map<MyDomainModel>(MyViewModel);
MyDomainModel = service.DoSomething();
Otherwise, if the method creates the new instance keeping some retaining some properties of the old one, you have to keep it:
public MyDomainModel DoSomething(MyDomainModel model)
{
MyDomainModel newModel = new MyDomainModel();
newModel.Property1 = model.Property1;
return newModel;
}
var MyViewModel = new MyViewModel();
var MyDomainModel = AutoMapper.Map<MyDomainModel>(MyViewModel);
MyDomainModel = service.DoSomething(MyDomainModel);
if the DoSomething method is changing the input parameter to point to a new object then you must use ref otherwise I don't see the point of passing by ref.
edit
if as you've mentioned within the comments that you're only changing the state of the input parameter then there is no need at all to return the reference to the object that was passed in because the changes will remain intact after the method call.
in fact, whether the input parameter is being passed by ref or not there shouldn't be a reason to return the same reference of the object passed in. so, therefore, you can make the method service.DoSomething(MyDomainModel); return void.
It depends what the method does. Objects are always passed by reference in this manner of use (though simply saying "passed by reference" doesn't really go far enough to explain what happens under the hood), so if DoSomething manipulates MyDomainMidel the changes will survive when the method returns. If, however, DoSomething makes a new domain model instance and returns it, and you want to preserve it, you have to keep the returned value
Here are some examples:
//the passed in person is renamed, you don't need to capture the return value
public Person Rename(Person p){
p.Name = "John";
return p;
}
//the passed in person is not renamed, you need to capture the return value
public Person Rename(Person p){
p = new Person();
p.Name = "John";
return p;
}
//the passed in person is swapped out for a new one, you don't need to capture the return value
public Person Rename(ref Person p){
p = new Person();
p.Name = "John";
return p;
}
The last example differs from the middle one thanks to the ref keyword. You can conceive that in the case if the middle call, you have a person in the calling method, you call Rename (myPerson) and the framework creates a copy of the reference to the person object, and passes the copy reference to the called method. If the called method manipulates properties of the instance then the original instance is modified even though it's accessed via a copy reference. If the copy reference is pointed to a whole new object, then any change to properties affect the new object, not the original. The copy reference goes out of scope when the method returns and the edits are lost as e copy pointer silently disappears, hence why you need to capture the return value if you want it
In the case of the ref keyword, rather than a copy of the reference to your myPerson being passed, the original reference to the instance is passed. If the method points it to a new object instance, then when control returns to the calling method, it will find its myPerson instance has been replaced with an entirely new object. The use cases for this are narrow, and it's not a favoured way to program because it essentially gives the called method the power to manipulate things beyond its scope of responsibility; the calling method might not appreciate having its variable contents trashed and replaced by a method call. There is nearly always a way to avoid using ref and while you're unclear on the mechanics of it, it is best to avoid using it, even if it does mean you have to code like the middle example.
You code like the middle example a lot, perhaps without realising; strings are immutable, so every call to e.g, .Substring creates a new string representing the shorter sequence of characters, so you have to keep the return value. As a result, some developers fall into the habit even for methods that only manipulate properties of an existing object and never use the new keyword
Can I somehow get a reference to the instance I am creating using object initialiser
var x = new TestClass
{
Id = 1,
SomeProperty = SomeMethod(this)
}
"this" should point to the new TestClass instance I'm creating. But it obviously refers the the instance of the class in which this code resides.
I'm not asking if this is a good way to do this.
I'm aware that I can do this like this:
var x = new TestClass {Id= x};
x.SomeProperty = SomeMethod(this);
I have a complicated scenario, in which a reference to the new instance in the object initialiser would make life easier.
Is this possible in any way?
There's no way around it, the C# specification explicitly says that "It is not possible for an object or collection initializer to refer to the object instance being initialized."
As for why it's impossible, I suspect that there's just no nice way to implement it. We want some syntactic sugar equivalent to
var temp = new TestClass();
temp.Id = 1;
temp.SomeProperty = SomeMethod(temp);
x = temp;
We just need a keyword to refer to temp within the initializer, but none is easily available. We can't use this because it already means something outside the initializer. Should SomeProperty = this.SomeMethod(this) be equivalent to temp.SomeProperty = this.SomeMethod(temp) or temp.SomeProperty = temp.SomeMethod(temp)? The second is consistent, but then what happens if we need the first?
We could try to use x, though we can only pick a name if the new object is immediately assigned to a variable. However, we now can't refer to the old value of x inside the initializer, doing the equivalent of temp.SomeProperty = SomeMethod(x).
We could reuse the value keyword from property setters. This sounds good since value already stands in for the missing parameter if you consider a property getter to be syntactic sugar for a set_SomeProperty(value) method. Using it to also refer to the missing variable in the object initializer looks promising. However, we could be creating this object inside a property setter, in which case value is already being used, and we need to be able to do temp.SomeProperty = SomeMethod(value).
It looks like we'll have to create a new keyword just for this purpose, maybe newthis. However, this is a breaking change to the language because any code that has a variable called newthis doesn't work any more. Microsoft generally needs a really good reason to introduce breaking changes, so it's better to forbid access to the object being initialized.
No, you can't use the object initializer to assign the object you're creating somewhere else - that defeats the whole point of the object initializer. The x variable doesn't get assigned until after the object initializer is completed. You'll need to assign the object, then use it in a separate statement.
var x = new TestClass {
Id = 1
};
x.SomeProperty = SomeMethod(x);
Exposing or using an object that hasn't been fully constructed is usually a very bad idea. Consider the following:
class Connection
{
internal string connectionString;
public Connection(ConnectionPool pool, string connectionString) {
this.pool = pool;
//this.connectionString = connectionString; // I moved it because I could.
this.pool.Register(this);
this.connectionString = connectionString;
this.Init();
}
private void Init() { //blah }
}
class ConnectionPool
{
public void Register(Connection c)
{
if ( this.connStrings.Contains( c.connectionString ) ) // BOOM
}
}
This is an extremely contrived example. Things can get a whole lot worse than this. The following was quite an interesting link regarding this issue:
Partially Constructed Objects
var x = new TestClass
{
Id = 1,
SomeProperty = SomeMethod(this)
}
Before the right part of this initialization is evaluated and executed, the reference to the new object is not yet made available to the code. That is done for security purposes, otherwise you could create some deadlock or endless loop with you code.