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.
Related
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'm not sure of the terminology for this kind of code, but I want to know if it's possible to instantiate variables after the parentheses, but whilst using reflection.
I have a map which gets loaded from an XML file. This is a collection of (int X, int Y, string S) where the X,Y is the position of some terrain, and S is a string representing the type of the terrain. I have a dictionary to pass between the strings and the relevant types; for example one key-value pair might be "Tree", typeof(Tree).
When using reflection, although I know it's possible to instantiate with parameters, the only way I'm comfortable is just by using Activator.CreateInstance(Type t), i.e. with an empty constructor.
When I had the maps hard coded, I would originally instantiate like this (within some i,j for loop):
case: "Tree"
world.Add( new Tree(i,j) );
Whilst starting to think about reflection and my save file, I changed this to:
world.Add( new Tree() { X = i, Y = j }
However, I realised that this won't work with reflection, so I am having to do the following (Tree inherits from Terrain, and the dictionary just converts the XML save data string to a type):
Type type = dictionary[dataItem.typeAsString];
Terrain t = (Terrain)Activator.CreateInstance(type);
t.X = i;
t.Y = j;
world.Add(t);
I would prefer to do this using something like
Type type = dictionary[dataItem.typeAsString];
world.Add((Terrain)Activator.CreateInstance(type) { X = i, Y = j }
Is there any shortcut like this? I guess if not I could edit world.Add to take an X and Y and cast to Terrain in there to access those variables, but I am still curious as to a) what this {var1 = X, var2 = Y} programming is called, and b) whether something similar exists when using reflection.
This syntax is called Object Initializer syntax and is just syntactic sugar for setting the properties.
The code var result = new MyType { X = x } will be compiled to this:
MyType __tmp = new MyType();
__tmp.X = x;
MyType result = __tmp;
You will have to do that yourself using PropertyInfo.SetValue if you know the instantiated type only at runtime or use the normal property setters if the type is known at compile time.
The answer is no, because the object initialization syntax you mention (introduced with LINQ in 3.0) is an illusion of the compiler. As in, when you type this
var foo = new Foo { Bar = "baz" };
the compiler actually converts it into CLS-compliant IL which equates to
var foo = new Foo();
foo.Bar = "baz";
Phil Haack has a great blog post which not only covers the details of this rewriting done by the compiler, but also some side effects it can cause when dealing with types that implement IDisposable
As all of this is nothing but a feint by the compiler, there is no equivalent using reflection (i.e., Activator.CreateInstance(Type t)). Others will give you workarounds, but in the end there really is no direct equivalent.
Probably the closest generic hack you could manage would be to create a method that accepted an object, then used reflection in order to identify the properties of that object and their respective values in order to perform object initialization for you. It might be used something like this
var foo = Supercollider.Initialize<Foo>(new { Bar = "baz" });
and the code would be something like (this is off the top of my head)
public sealed class Supercollider
{
public static T Initialize<T>(object propertySource)
{
// you can provide overloads for types that don't have a default ctor
var result = Activator.CreateInstance(typeof(T));
foreach(var prop in ReflectionHelper.GetProperties(typeof(T)))
ReflectionHelper.SetPropertyValue(
result, // the target
prop, // the PropertyInfo
propertySource); // where we get the value
}
}
You'd have to get each property from the anonymous object, find a property in your target type with the same exact name and type, then get the value from that property in the anonymous object and set the value of your target's property to this value. Its not incredibly hard, but its absolutely prone to runtime exceptions and issues where the compiler chooses a different type for the anonymous type's property, requiring you be more specific (e.g., new { Bar = (string)null }), which screws with the elegance of the thing.
(T)Activator.CreateInstance(typeof(T), param1, param2, ...);
As described HERE.
public sealed class ReflectionUtils
{
public static T ObjectInitializer<T>(Action<T> initialize)
{
var result = Activator.CreateInstance<T>();
initialize(result);
return result;
}
}
public class MyModel
{
public string Name{get;set;}
}
And after that just make the call :
var myModel = ReflectionUtils.ObjectInitializer<MyModel>(m =>
{
m.Name = "Asdf"
});
The advantage is that in this way you will have type safety and use reflection as minimum required, because we all know that reflection is an expensive operation that should be avoided as much as possible.
You could create a constructor which takes those arguments, then use
Activator.CreateInstance(type, i, j)
But you won't be able to use the object initialization syntax. Which is just sugar candy for setting the properties.
var sharedViewModel=new SharedViewModel;
var viewModel1 = new ViewModel1(ref sharedViewModel)
var viewModel2 = new ViewModel2(ref sharedViewModel)
var viewModel3 = new ViewModel3(ref sharedViewModel)
will there be a difference if i do
var viewModel1 = new ViewModel1(sharedViewModel)
var viewModel2 = new ViewModel2(sharedViewModel)
var viewModel3 = new ViewModel3(sharedViewModel)
ViewModel1,ViewModel2,ViewModel3 will be doing changes to the SharedViewModel instance, is there a difference between ref SharedViewModel and SharedViewModel in this case?
Edit:
Example of what will be inside my ViewModel1,ViewModel2,ViewModel3 classes
private SharedViewModel sharedvm;
Public ViewModel(SharedViewModel sharedViewModel)
{
sharedvm=sharedViewModel;
sharedvm.Collection.Add(new object());
}
private doSomthing()
{
sharedvm.Collection.RemoveAt(0);
}
now the question is if i add an object to my sharedvm collection, does that mean that i am adding an object to my sharedViewModel collection?
what about if i call the doSomthing method, will the changes reflect on my sharedViewModel?
Yeah there is a difference.
The value of SharedViewModel can be different because you are passing a reference to a reference (essentially the sharedViewModel variable itself) to the the ViewModel1 constructor.
So if SharedViewModel is changed in the ctor, then it will affect the variable in the calling scope.
By changed I mean in the ViewModel1 ctor you do this:
sharedViewModel = new SharedViewModel()
Perhaps, I wasn't clear enough.
If you've done C/C++ think of it this way.
object *a = new object()
object **b = &a
func(b)
But you still have a high level view because everything is done by the compiler.
EDIT:
First case
public ViewModel(SharedViewModel sharedViewModel)
{
sharedvm=sharedViewModel;
sharedvm.Collection.Add(new object());
}
versus second case
public ViewModel(ref SharedViewModel sharedViewModel)
{
sharedvm=sharedViewModel;
sharedvm.Collection.Add(new object());
}
In this scenario, there is absolutely no difference. The same collection in the heap is being modified. So what happens to the collection can be seen by the calling scope.
The difference occurs when in the first case you do this:
sharedViewModel = new SharedViewModel()
Now you are modifying a completely different object in memory, and the changes applied to that object's collection is not seen by the calling scope because the calling scope references a completely different object.
So usually you never new the argument you just passed in. But if for some reason you do new the argument, then the ref keyword is a way to circumvent the said problem.
No, because instance of SharedViewModel is a reference type sa already passed by as reference.
For me you should't use ref in this case.
Ref could be usefull if you want to pass non-reference type (eg. primitive types as int) as reference, so as a pointer.
As you could read on msdn, about ref
Do not confuse the concept of passing by reference with the concept of reference types. The two concepts are not the same. A method parameter can be modified by ref regardless of whether it is a value type or a reference type. There is no boxing of a value type when it is passed by reference.
Classes are already passed by reference. You don't need ref keyword at all.
Looking at this Microsoft article How to: Write a Copy Constructor (C#) and also this Generic C# Copy Constructor, wouldn't it be best/safe to use a reference to the class instance than to use a plain copy of the instance ?
public class Myclass()
{
private int[] row;
public MyClass(ref MyClass #class)
{
for(int i = 0; i<#class.row.Length;i++)
{
this.row[i] = #class.row[i];
}
}
}
What ref actually means:
void Change(SomeClass instance)
{
instance = new SomeClass();
}
void ChangeRef(ref SomeClass instance)
{
instance = new SomeClass();
}
Later...
SomeClass instance = new SomeClass();
Change(instance);
//value of instance remains unchanged here
ChangeRef(ref instance);
//at this line, instance has been changed to a new instance because
//ref keyword imports the `instance` variable from the call-site's scope
I can't see how this functionality would be useful with respect to a copy constructor.
Object by nature is reference not a value type. I do not see any good reason what extra advantage you would get doing it. But yes you might get into problems because of it, consider this -
You created an object and passed it with reference to couple of classes and those classes are now having access to the address of reference itself. Now I have got all the powers to go and change the reference itself with another object's reference. If here, another class had this object it is actually working on some stale object and other classes can not see what changes are being made and you are in chaos.
I do not see any use of doing it, rather it is dangerous. It does not sounds like a OO way of writing code to me.
The ref keyword is used when a method should be allowed to change the location of a reference. Reference types always pass their reference into a method (but the location of the reference cannot be modified via assignment). Values types pass their value.
See: Passing Parameters
Example:
void PassingByReference(List<int> collection)
{
// Compile error since method cannot change reference location
// collection = new List<int>();
collection.Add(1);
}
void ChangingAReference(ref List<int> collection)
{
// Allow to change location of collection with ref keyword
collection = new List<int>();
collection.Add(2);
}
var collection = new List<int>{ 5 };
// Pass the reference of collection to PassByReference
PassingByReference(collection);
// collection new contains 1
collection.Contains(5); // true
collection.Contains(1); // true
// Copy the reference of collection to another variable
var tempCollection = collection;
// Change the location of collection via ref keyword
ChangingAReference(ref collection);
// it is not the same collection anymore
collection.Contains(5); // false
collection.Contains(1); // false
// compare the references use the default == operator
var sameCollection = collection == tempCollection; // false
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 .....