Given object initializers:
Foo foo = new Foo{ Name = "Jhon", Value = 2, IsMale = true };
Can they be somehow used elsewhere?(outside object construction) So that insted of using:
foo.Name = "Name";
foo.Value = 5;
...
foo.DoSth();
To just use something like:
Name = "Name";
Value = 5;
...
DoSth();
Given that this is outside the class hierarchy of foo. That is to avoid places where you use one object's members many many times.
For example in VB/GML(GameMaker's scripting language) one can use:
with(foo)
{
Name = "Name";
Value = 5;
...
DoSth();
}
Instead of foo.something
So is there something like this in C#?
No, object initializer is the only place where assignment syntax like that can be used. If you need to assign multiple fields at once from many different places in code without duplication, you could define a method that encapsulates all the assignments for you:
void SetNameAndGender(string f, string l, bool isMale) {
FirstName = f;
LastName = l;
IsMale = isMale;
}
Unfortunately, it does not let you set an arbitrary group of properties, like the VB syntax that you show.
Related
I've came across this code:
var rectangle = new Rectangle(420, 69);
var newOne = rectangle with { Width = 420 }
I was wondering about with keyword in C# code. What is it for? And how can it be used? And what benefits does it bring to the language?
It's an operator used in expressions for easier duplication of an object, overriding some of it's public properties/fields (optional)
with expression - MSDN
Currently it can only be used with records. But maybe there will be no such restriction in the future (assumption).
Here's an example how it can be used:
// Declaring a record with a public property and a private field
record WithOperatorTest
{
private int _myPrivateField;
public int MyProperty { get; set; }
public void SetMyPrivateField(int a = 5)
{
_myPrivateField = a;
}
}
Now let's see how with operator can be used:
var firstInstance = new WithOperatorTest
{
MyProperty = 10
};
firstInstance.SetMyPrivateField(11);
var copiedInstance = firstInstance with { };
// now "copiedInstance" also has "MyProperty" set to 10 and "_myPrivateField" set to 11.
var thirdCopiedInstance = copiedInstance with { MyProperty = 100 };
// now "thirdCopiedInstance " also has "MyProperty" set to 100 and "_myPrivateField" set to 11.
thirdCopiedInstance.SetMyPrivateField(-1);
// now "thirdCopiedInstance " also has "MyProperty" set to 100 and "_myPrivateField" set to -1.
NOTE for reference types from MSDN:
In the case of a reference-type member, only the reference to a member instance is copied when an operand is copied. Both the copy and original operand have access to the same reference-type instance.
That logic can be modified by modifying the copy constructor of a record type. Quote from MSDN:
By default, the copy constructor is implicit, that is, compiler-generated. If you need to customize the record copy semantics, explicitly declare a copy constructor with the desired behavior.
protected WithOperatorTest(WithOperatorTest original)
{
// Logic to copy reference types with new reference
}
And in terms of what benefits it gives, I think it should be quite obvious now, that it makes copying of instances much easier and convenient.
Basically, the with operator will create a new object instance (records only, for now), by "coping values" from the "source" object and override some named properties in the destination object.
For example, instead of doing this:
var person = new Person("John", "Doe")
{
MiddleName = "Patrick"
};
var modifiedPerson = new Person(person.FirstName, person.LastName)
{
MiddleName = "William"
};
you can do this:
var modifiedPerson = person with
{
MiddleName = "Patrick"
};
Basically, you will write less code.
Use this source to get more details on the example above and official documentation for more examples.
Short answer is the following:
with keyword in C# was added for easier copy of complicated objects, with a possibility to override some of the public properties.
Examples are already briefly provided in the accepted answer.
Currently I am receiving an array of objects from a database.
object [] sqlResultData = DatabaseCall.Result();
This array of objects needs to be matched to class variables like this
CClassOfVars classVar = new CClassOfVars();
classVar.myProperty = sqlResultData[0];
classVar.myProperty1 = sqlResultData[1];
What i wish to do is pass the list of propertys on the class in order to a function and have the mapping from the object array occur automatically based on the order.
For example:
Method defined like this
FillData(object [] databaseValues, IList<object>())
Called like this
CClassOfVars classVar = new CClassOfVars();
object [] sqlResultData = DatabaseCall.Result();
FillData(sqlResultData, new List<object>(){classVar.myProperty,classVar.myProperty1});
The FillData function would hopefully type cast and set the values of myProperty and myProperty1 to the values in array locations of 0,1 etc...
Something like this
FillData(object [] databaseValues, IList<object> mapMe)
{
for (int i = 0; i < mapMe.Count; i++)
{
mapMe[i] = CastToTheCorrectType(mapMe[i], databaseValues[i]);
}
}
Cast to the correct type could look like this?? I took from here: cast object with a Type variable
public T CastToTheCorrectType<T>(T hackToInferNeededType, object givenObject) where T : class
{
return givenObject as T;
}
How can i pass a list of different object types to all have there values modified and assigned within a different function?
The matter you asking about is dark and difficult to be implemented through just a function. There are frameworks out there dealing with object relational mapping. If it is an option, install and learn some OR/M. If not ... well, there might be some dirty way.
You can use the JSON.NET library to do the heavy lifting for you. It's super easy to use and install through Nuget. My point is as follows.
Construct an anonymous object. Use the property names of the original object.
Fill it with the data from the object array. Spin a loop over the object array...
Serialize the anonymous object.
Deserialize the JSON string into the target type.
At this point, JSON.NET will handle property mapping for you.
List item
E.g. if your target type is Person you might do this:
var x = new
{
FirstName = String.Empty,
LastName = String.Empty
};
var persons = new List<Person>(sqlResultData.Length);
foreach (var record in sqlResultData)
{
x.FirstName = record[0];
x.LastName = record[1];
var s = JsonConvert.SerializeObject(x)`
var personX = JsonConvert.Deserialize<Person>(s);
persons.Add(person);
}
I have just a silly doubt that below is my small piece of code.
IDictionary<string, string> dic = new Dictionary<string, string>();
IDictionary<Demo, string> dic2 = new Dictionary<Demo, string>();
dic.Add("S1", "S1.1");
dic.Add("S1", "S1.1");
Demo d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "1");
d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "2");
So my question is i am getting exception at line no 4 which is correct according to dictionary concept that I can not add duplicate key in Dictionary however when I am trying to do same thing with object and object with same name I am not getting any exception event Dictionary have now two object of same type and same name.
Please help to understand this concept.
When inserting data into dictionary, Equals is used to check wheter key is unique.
In string Equals is implemented to check its value. That is why you cannot insert two strings into dictionary. What's more string is strange type - technically it is reference type, but acts like value type.
In bare object (or when not overriden), Equals is implemented to compare object by reference - it just checks wheter variabled points to the same area of memory (note: we are talking about classes, not structs :-)). So when you create two objects:
Demo d1 = new Demo() { MyProperty = 1 };
d1 = new Demo() { MyProperty = 1 };
There are two copies of that object in different place in memory, so Equals says: "That objects are different" - and you can add it to the dictionary.
You can of course change this behaviour by overriding Equals (and GetHashCode but here is skipped to keep answer clear) in Demo:
public override bool Equals(object obj)
{
// If parameter cannot be cast to Demo or is null return false.
Demo p = obj as Demo;
if (p == null)
{
return false;
}
// Return true if the fields match:
return (MyPropertyx == p.MyProperty));
}
Then:
Demo d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "1");
d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "2");
will not definitely allow to insert second value.
In C# strings behave like value types which means that the value of the string is compared (which is called Value Equality), meaning:
var string1 = "S1";
var string2 = "S1";
Console.WriteLine(string1 == string2) // will output true
In the case of objects (such as your Demo object) by default when they are compared they are only checked to see if they are the same object (which is called Reference Equality), meaning:
var d1 = new Demo() { MyProperty = 1 };
var d2 = new Demo() { MyProperty = 1 };
Console.WriteLine(d1 == d2) // will output false
Now with objects you can implement Value Equality so that the above example will output true.
You can learn more about that with this guideline.
You have two objects using the same variable name (d1) but they refer to different instances of an object - so there is no duplicate.
It also looks like you expect both objects to be the "same" based on both having a property MyProperty with the value 1. This is not the case - the dictionary, by default, will use the references as the key, which are different as I mentioned above. To enable the dictionary to treat your two objects as the same you would need to override Equals and GetHashCode in your class Demo
Suppose I have a very large list of objects and each object in the list has the following properties: ID, Name, Make, Model, Color, Price
I know that if I want to quickly locate an object in the list I can use an Indexer and search for the object using it's ID.
But once I locate the object how do I change more than one property at the same time?
I thought about returning the MyClass Object in the get property of the Indexer so that I have access to all of its properties. However, I don't know what to do in the set property of the Indexer to make it work. Below is my code
public MyClass this[int id]
{
get {return myObjectList.FirstOrDefault(item => item.ID == id);}
set {// something = value;}
}
But once I locate the object how do I change more than one properties at the same time?
It looks like you want to do something like
List[4] = {Name = "name",
Make = "make",
Model = "model",
Color = "color",
Price = "price
};
Which is not possible in C#. There's no syntax to set multiple properties of an existing object simultaneously. You can create a new object and replace the one in the list:
List[4] = new MyClass {
Name = "name",
Make = "make",
Model = "model",
Color = "color",
Price = "price
};
But that's creating a new object, not modifying an existing one.
The only way to set multiple properties is with individual sets:
MyClass obj = List[4];
obj.Name = "name";
obj.Make = "make";
obj.Model = "model";
ojb.Color = "color";
obj.Price = "price";
Note that this does not involve the setter of the index property at all. It's not uncommon for collections to have a get-only indexer so that the list itself cannot be mutated through the indexer, although the properties of the objects inside can.
Info myPath = new Info()
{
path = oFile.FileName
};
...
class Info
{
public string path;
public string Path
{
get { return path; }
set { path = value; }
}
}
Above is the C# code from some program and it can work normally. But I don't understand it well. The first question is that why path = oFile.FileName is not written as path = oFile.FileName; ? Why the semicolon can be removed?
The second question is that why I cannot write it like this: myPath.path = oFile.FileName ? There will give error message by Visual Studio 2012.
That construct is an object initializer. It's not a list of arbitrary statements - it's only initialization of fields and properties, and they're comma-separated:
Foo x = new Foo // Implicitly calls the parameterless constructor
{
Property1 = value1,
Property2 = value2
};
That's shorthand for:
Foo tmp = new Foo();
tmp.Property1 = value1;
tmp.Property2 = value2;
Foo x = tmp;
Object initializers were introduced in C# 3, along with collection initializers which are effectively syntactic sugar for repeated calls to Add. So:
List<string> names = new List<string>
{
"Foo", "Bar"
};
is equivalent to:
List<string> tmp = new List<string>();
tmp.Add("Foo");
tmp.Add("Bar");
List<string> names = tmp;
You have many ways of initializing an object in C#.
Here you can do what you have written, which will be an equivalent to this:
Info myPath = new Info();
myPath.Path = oFile.FileName;
this syntax
Info myPath = new Info()
{
path = oFile.FileName
};
is just a shortcut, and can be more readable, but will do the same thing. Actually it seems that it was kind of taken from VisualBasic (the With statement).
To explain the above syntax:
YourClassName <your_variable> = new YourClassName()
{
<property_name> = value,
<anotherProperty> = value,
...
<last_property> = value
};
the last way is to have a constructor that takes the path as an argument and initializes it. This is actually the way where there is the less operations done by the cpu (but it's not significant).
In C# 3.0, they added a new & helpful feature for initializing objects as a single statement/expression.
Whereas before, you'd have to issue separate statements:
Info myPath = new Info();
myPath.Filename = ...
myPath.AnotherProperty = ...
myPath.AnotherAnotherProperty = ...
You can now perform the same assignments in one step:
Info myPath = new Info
{
Filename = ...
AnotherProperty = ...
AnotherAnotherProperty = ...
};
This is especially useful, for constructing objects in Linq queries (without having to custom-code object constructors).
For example:
someList.Select(x => new SomethingElse{ SomeProperty = x.Something });
Info myPath = new Info()
{
path = oFile.FileName
};
means:
Initialize a new Info Class and add to property path the value oFile.FileName
it is the short version of:
Info myPath = new Info();
myPath.path = oFile.FileName;
you do not need ';' because you can stack more properties in the brackets like this:
Person p = new Person()
{
Name = "John",
Age = 25
};
C# allows you to initialize properties of an object at the same time that you're constructing it.
These are all equivalent:
var foo = new Foo();
foo.Property = "Bar";
foo.AnotherProperty = 12;
var foo = new Foo()
{
Property = "Bar",
AnotherProperty = 12
};
// The parentheses are not really necessary for parameterless constructors
var foo = new Foo
{
Property = "Bar",
AnotherProperty = 12
};
It is the new way of initializing variables in C#. You can also skip '()' signs.
You can initialize like that also lists, arrays, etc. in brackets you must insert elements which you want to initialize in your object.
Info myPath = new Info()
{
path = oFile.FileName
};
is equivalent to
Info myPath = new Info();
myPath.path = oFile.FileName;
When initializing with the object initializing structure, you create a list of property assignments as you noted. This way you can create objects and assign variables in one call without having an explicit constructor. The above could easily have been written in one line.
More info can be found on the MSDN website.