I created a string[] getter to get some information on a class. I want it to always return the same value, and not create a new object on each call.
I have it implemented now like this:
string[] _someStrings = { "foo", "bar" };
protected string[] someStrings {
get {
return _someStrings;
}
}
which seem to be OK. However, my first inkling was to write it like this:
protected string[] someStrings {
get {
return { "foo", "bar" };
}
}
but that doesn't work (I get the error ; expected).
Why?
(this is mainly a "getting-to-understand-C# question).
update I made a typo. I do not want to create a new object on each call.
The correct syntax would be this:
return new [] { "foo", "bar" };
The reason is that the short syntax without new [] is only valid for an assignment.
As you correctly note in a comment, this will create a new object on every call. The only way to avoid this is with a field that stores the created instance and return that field. This is exactly the solution you already have.
Please note however, that this allows consumers to change the contents of the array and affect other consumers:
var a1 = foo.SomeStrings;
var a2 = foo.SomeStrings;
a1[0] = "Some other value";
Assert.Equal("Some other value", a2[0]); // will pass
As an alternate approach, may I suggest, if the contents are supposed to be constant, using a read-only collection instead, such that:
private readonly ReadOnlyCollection<string> UnderlyingReadOnlyStrings;
// populate the read-only collection, then...
public ReadOnlyCollection<string> ReadOnlyStrings {
get { return UnderlyingReadOnlyStrings; }
}
The benefit here is that your collection truly is read-only. And practically constant. It can't be re-assigned to, and the contents cannot be altered. You could even declare the underlying collection as static and populate in a static constructor.
Your second example doesn't work, as previously explained, because you're trying to return an "inline array", so to speak, and the syntax is not correct, and if it were, you would be newing the array each time - which goes against your requirements.
Your syntax is incorrect. Try this:
protected string[] someStrings
{
get
{
return new string[] { "foo", "bar" };
}
}
You can't have const array, but you can have a readonly one that will work as you expect (can also be static, obviously):
public readonly string[] someStrings = { "foo", "bar" };
Related
So I'm working with code in which there are two object that contain each other, inside a list of which I do not know the contents of until runtime. I have a function that needs to convert the first object to a third object, but to do such I need to convert the second object aswell, however to do that I will need the convert the first, and here is the chicken and the egg problem.
Problem Example
namespace chicken // Also I like formatting my code like this, so don't judge me
{
public class Object1 { // Object One and Two are of the same class
public List<dynamic> contents = new List<dynamic>();
public Object1() {}
public Object1(List<dynamic> contents) {
this.contents = contents;
}
}
public class Object3 {
public string name;
public Object3 friend;
public string pet;
public Object3(List<dynamic> converted) {
this.name = converted[0];
this.friend = converted[1];
this.pet = converted[2];
}
}
public class Program {
public static void Main(string[] args) {
Object1 object1 = new Object1(); // Just to create the problem, they don't
Object1 object2 = new Object1(); // get created like this in the actual code
object1.contents = new List<dynamic> {
"Steve Johnson", // This is example data, this order is supposed to be unknown
object2,
"Biscut",
};
object2.contents = new List<dynamic> {
"Bob Smith",
object1,
"Tiny",
};
Object3 final = convert(object1); // Runs the conversion function
}
public static Object3 convert(Object1 obj) {
List<dynamic> converted = new List<dynamic>(); // I need a sanitized list for Object3
for (int i = 0; i < obj.contents.Count; i++) {
if (obj.contents[i] is Object1) {
converted.Add(convert(obj.contents[i])); // Causes infinite loop due to chicken and egg problem
continue;
} converted.Add(obj.contents[i]);
}
Object3 object3 = new Object3(converted); // Again the list order is unknown
return object3;
}
}
}
I've tried using references, where there is a tunnel object and 'Object3' passes references to it's varibles to it, so I can semi construct Object3, put it in a cache, pass it to object 2 to convert it, then put in the values though the tunnel object containing the references. This got to complicated and I honestly don't know what to do without having an empty constuctor for Object 3.
The problem you're describing can be simplified down to this:
In the following code, how can we make it so Node a references b and b references a?
Node a, b;
a = new Node(new object[] { b });
b = new Node(new object[] { a });
public record Node(IEnumerable<object> Links);
You already hit on the solution: allow a Node to be constructed without all of its possible objects, so you can construct the Nodes first, and then insert them where they belong. It sounds like you don't want to give Node ("Object3") a default constructor, but the way you've implemented it at the moment, it should still be possible to add values after the fact, if you can add to its items list after its construction.
List<object> aList = new(), bList = new();
Node a = new Node(aList), b = new Node(bList);
aList.Add(b);
bList.Add(a);
If that will work for you, then the rest is just the details you've described:
using references, where there is a tunnel object and 'Object3' passes references to its variables to it, so I can semi construct Object3, put it in a cache, pass it to object 2 to convert it, then put in the values though the tunnel object containing the references.
It may be complicated, but that's pretty much what has to happen.
If, for some reason, you need your Object3 class structure to be immutable, so you cannot change its contents after its construction, then you're at an impasse: your requirements are clearly impossible. You're defining an object that must be constructed with all its dependencies, but its dependencies need it to be constructed before they can be constructed.
Here is a minimal representation of your code:
namespace chicken
{
public class Program
{
public static void Main(string[] args)
{
List<dynamic> chicken1 = new List<dynamic> { "Steve Johnson", null, "Biscut", };
List<dynamic> chicken2 = new List<dynamic> { "Bob Smith", chicken1, "Tiny", };
chicken1[1] = chicken2;
Convert(chicken1);
}
public static void Convert(List<dynamic> chicken)
{
foreach (dynamic inner in chicken)
{
if (inner is List<dynamic>)
{
Convert(inner);
}
}
}
}
}
You've just created two dynamic lists that refer to each other and then you try to recursively navigate from one list to the other infinitely.
There is nothing about an egg is your scenario that causes your problem. And, there's very little to do with chickens either, as you really only have two dynamic lists.
I suspect you have a real-world example that may have a chicken versus egg problem, but you haven't translated it into your question.
The bottom-line for me is that there are very few good uses for the keyword dynamic. In 99% of cases it's just syntactic sugar for adding bugs in your code.
The following combination of object and collection initializers does not give compilation error, but it is fundamentally wrong (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#examples), because the Add method will be used in the initialization:
public class Foo
{
public List<string> Bar { get; set; }
}
static void Main()
{
var foo = new Foo
{
Bar =
{
"one",
"two"
}
};
}
So you'll get NullReferenceException. What is the reason for making such an unsafe decision while developing the syntax of the language? Why not to use initialization of a new collection for example?
First, it's not only for combination of object and collection initializers. What you are referring here is called nested collection initializers, and the same rule (or issue by your opinion) applies to nested object initializers. So if you have the following classes:
public class Foo
{
public Bar Bar { get; set; }
}
public class Bar
{
public string Baz { get; set; }
}
and you use the following code
var foo = new Foo
{
Bar = { Baz = "one" }
};
you'll get the same NRE at runtime because no new Bar will be created, but attempt to set Baz property of the Foo.Bar.
In general the syntax for object/collection initializer is
target = source
where the source could be an expression, object initializer or collection initializer. Note that new List<Bar> { … } is not a collection initializer - it's an object creation expression (after all, everything is an object, including collection) combined with collection initializer. And here is the difference - the idea is not to omit the new, but give you a choice to either use creation expression + object/collection initializer or only initializers.
Unfortunately the C# documentation does not explain that concept, but C# specification does that in the Object Initializers section:
A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.
and
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the target field, property or indexer, the elements given in the initializer are added to the collection referenced by the target.
So why is that? First, because it clearly does exactly what you are telling it to do. If you need new, then use new, otherwise it works as assignment (or add for collections).
Other reasons are - the target property could not be settable (already mentioned in other answers). But also it could be non creatable type (e.g. interface, abstract class), and even when it is a concrete class, except it is a struct, how it will decide that it should use new List<Bar> (or new Bar in my example) instead of new MyBarList, if we have
class MyBarList : List<Bar> { }
or new MyBar if we have
class MyBar : Bar { }
As you can see, the compiler cannot make such assumptions, so IMO the language feature is designed to work in the quite clear and logical way. The only confusing part probably is the usage of the = operator for something else, but I guess that was a tradeoff decision - use the same operator = and add new after that if needed.
Take a look at this code and the output of it due to the Debug.WriteLine():
public class Foo
{
public ObservableCollection<string> _bar = new ObservableCollection<string>();
public ObservableCollection<string> Bar
{
get
{
Debug.WriteLine("Bar property getter called");
return _bar;
}
set
{
Debug.WriteLine("Bar allocated");
_bar = value;
}
}
public Foo()
{
_bar.CollectionChanged += _bar_CollectionChanged;
}
private void _bar_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Debug.WriteLine("Item added");
}
}
public MainWindow()
{
Debug.WriteLine("Starting..");
var foo = new Foo
{
Bar =
{
"one",
"two"
}
};
Debug.WriteLine("Ending..");
}
The output is:
Starting..
Bar property getter called
Item added
Bar property getter called
Item added
Ending..
For you questions:
What is the reason for making such an unsafe decision while developing the syntax of the language? Why not to use initialization of a new collection for example?
Answer:
As you can see the intention of the designer of that feature was not to reallocate the collection but rather to help you add items to it more easily considering that you manage your collection allocation by yourself.
Hope this clear things out ;)
Consider the following code:
class Program
{
static void Main()
{
var foo = new Foo
{
Bar =
{
"one",
"two"
}
};
}
}
public class Foo
{
public List<string> Bar { get; set; } = new List<string>();
}
The compiler does not know whether you already created a new list instance within the class constructor (or in another method).
Recall that collection initializer is a series of calls to Add method on an existing collection!
See also:
Custom Collection Initializers
Also note that this initializer applies to a collection that was exposed as a property. Hence the collection initializer is possible as part of the outer object initializer (the Foo object in your example).
However, if it was a simple variable, the compiler would not let you to intialize the collection this way. Here is an example:
List<string> list =
{
"one",
"two"
};
This will throws a compilation error.
As last example, the output of the following code will be: "one, two, three, four, ". I think that now you understand why.
Pay attention to the list static instance, as well as to the private modifier in the "set" of the Bar property, which does not matters because the initializer just calls the Add method, which is accessible even when the Bar "set" is private.
class Program
{
static void Main()
{
var foo1 = new Foo
{
Bar =
{
"one",
"two"
}
};
var foo2 = new Foo
{
Bar =
{
"three",
"four"
}
};
PrintList(foo1.Bar);
}
public static void PrintList(List<string> list)
{
foreach (var item in list)
{
Console.Write(item + ", ");
}
Console.WriteLine();
}
}
public class Foo
{
private static readonly List<string> _bar = new List<string>();
public List<string> Bar { get; private set; } = _bar;
}
I believe the key thing to understand here is that there are two syntactic sugar flavors at play (or at least, there should be):
Object Initialization
Collection Initialization
Take away the List for a moment and look at the field as an object:
public class Foo
{
public object Bar { get; set; }
}
When using Object Initialization, you assign an object (or null):
var foo = new Foo()
{
Bar = new object(); //or Bar = null
}
Now, let's go back to your original example and slap Collection Initialization on top of this. This time around, the compiler realizes this property implements IEnumerable and the array you have provided is of the right type, so it attempts to call the Add method of the interface. It must first go looking for the object, which in your case is null because you haven't initialized it internally. If you debug through this, you will find that the getter gets called and returns null, hence the error.
The correct way of mixing both features then would be for you to assign a new object that you initialize with your values:
var foo = new Foo()
{
Bar = new List<string>(){ "one", "two" }
};
If you debug this version, you will find that the setter is called instead, with the new instance you initialized.
Alternatively, you can initialize your property internally:
public List<string> Bar { get; set; } = new List<string>();
If you debug this version, you will find that the property is first initialized with a value and your version of the code then executes without error (by calling the getter first):
var foo = new Foo()
{
Bar = {"one", "two"}
};
To illustrate the syntactic sugar aspect, Collection Initialization only works within the confines of a constructor calling statement:
List<string> bar = {"one", "two" }; //ERROR: Can only use array initializer expressions to assign to array types. Try using a new expression instead.
List<string> bar = new[] { "one", "two" }; //ERROR: Cannot implicitly convert type 'string[]' to 'System.Collections.Generic.List<string>'
List<string> bar = new List<string>() { "one", "two" }; //This works!
If you wish to allow initialization like in your original example, then the expectation is that the variable will be set to an instance before the Add method can be called. This is true whether you use syntactic sugar or not. I could just as well run into the same error by doing this:
var foo = new Foo();
foo.Bar.Add("one");
So you may want to initialize the variable in order to cover all bases, unless of course a null value has a semantic meaning in your application.
Through some random object creation today I came across this neat little shortcut for a Dictionary<K, V>. Is the following assignment a compiler shortcut or is it a feature of Dictionary<string, string>.
IDictionary<string, string> items = { { "item1key", "item1value" } };
Looking at the source for Dictionary<K, V> I don't see anything offhand for how this works. Implementing all the interfaces for this class dot not allow me to perform a similar operation. Why is it that we can do it for a dictionary but not another type. For example, how does the compiler or language feature know that the first item is a key and the second item is the value. Or even more specific this same syntax can't be used for a List<string>
List<string> items = { "item1" };
So the first is valid, why?
I'm not necessarily trying to duplicate this but rather curious as to why it is the way it is. What makes a dictionary special in this case?
Example that works
public class Button
{
public string Title { get; set; }
public ButtonType Type { get; set; }
public IDictionary<string, string> Items { get; set; }
public bool RequiresSelected { get; set; }
}
var buttons = new List<Button>
{
new Button {
Items = {
{"button1", "Button 1"},
{"button2", "Button 2"},
{"button3", "Button 3"},
},
Title = "3 Buttons",
Type = ButtonType.DropDown
}
};
The syntax you've shown isn't valid in C#. You'd need:
IDictionary<string, string> items = new Dictionary<string, string>
{ { "item1key", "item1value" } };
At that point it's just a normal collection initializer, so the list equivalent would be:
List<string> items = new List<string> { "item1" };
EDIT: Let's see if my edit can beat yours. My guess is that you've seen something like:
var foo = new Foo {
SomeDictionaryProperty = {
{ "item1key", "item1value" }
}
};
That's an embedded collection initializer, and can be used for lists too. It's not creating a new dictionary, it's adding to an existing one. The code above is equivalent to:
var tmp = new Foo();
tmp.SomeDictionaryProperty.Add("item1key", "item1value");
var foo = tmp;
Another example of it working:
var form = new Form {
Controls = { new Label { Text = "Foo"}, new Label { Text = "Bar" } }
};
See section 7.6.10.2 of the C# 4 specification (Object Initializers) for more information. The important bit is this:
member-initializer:
identifier = initializer-value
initializer-value:
expression
object-or-collection-initializer
So you can initialize a property to either be a specific value (in which case the setter will be used) or via an object/collection initializer, in which case the getter for the property will be used, and then setters or the Add method will be used for the body of the object/collection initializer.
This is a feature of C# compiler, and the dictionary is not special: any collection that supports Add can be initialized in this way. The details are in the section 7.6.10.3 of the C# Language Specification 4.0.
The collection object to which a collection initializer is applied must be of a type that implements System.Collections.IEnumerable or a compile-time error occurs. For each specified element in order, the collection initializer invokes an Add method on the target object with the expression list of the element initializer as argument list, applying normal overload resolution for each invocation. Thus, the collection object must contain an applicable Add method for each element initializer.
It seems that string is reference, but copied by value
List<string> data = new List<string>();
string s = "a";
data.Add(s); // copy by value??
s = "b";
Console.WriteLine(data[0]); // "a"
It also seems that class is reference copied by reference
class boxstring { public string val; }
List<boxstring> data = new List<boxstring>();
boxstring s = new boxstring { val = "a" };
data.Add(s); // copy by reference, ok
s.val = "b";
Console.WriteLine(data[0].val); // "b"
Is there a simpler way to pass string into collection by reference without wrapping it into class? I'd like to pass object member into collection and if the object is changed, the collection should be also changed without writing extra code.
Strings are immutable, if you want the objects in your container to change, they must be mutable. Therefore, you must wrap them in a class like you did.
Strings are immutable. Whenever you assign new value to string variable, a new instance is created everytime that's why you can't see the updates in your collection.
However, .NET already provide mutable counterpart of string i.e. "StringBuilder". This will work for you -
List<StringBuilder> data = new List<StringBuilder>();
StringBuilder s = new StringBuilder("a");
data.Add(s);
s.Clear();
s.Insert(0, "b");
Console.WriteLine(data[0]); // "b"
Here's an idea to make you code simpler :
public MyString
{
public string Value{get;set;}
public MyString(string value)
{
Value=value;
}
public static implicit operator MyString(string value)
{
return new MyString(value);
}
public static implicit operator string(MyString mystring)
{
if(mystring==null) return null;
return mystring.Value;
}
then you can use MyString object whenever you want to have string by reference.since we have these implicit operator in place you can use MyString instead of string
You cannot pass intrinsic data-types by reference, they are always passed by value.
Intrinsic types include basic types like Int32, String, Bool, etc..
For the life of me, I cannot figure out what is going on in the example piece of C# code below. The collection (List) property of the test class is set as read only, but yet I can seemingly assign to it in the object initializer.
** EDIT: Fixed the problem with the List 'getter'
using System;
using System.Collections.Generic;
using NUnit.Framework;
namespace WF4.UnitTest
{
public class MyClass
{
private List<string> _strCol = new List<string> {"test1"};
public List<string> StringCollection
{
get
{
return _strCol;
}
}
}
[TestFixture]
public class UnitTests
{
[Test]
public void MyTest()
{
MyClass c = new MyClass
{
// huh? this property is read only!
StringCollection = { "test2", "test3" }
};
// none of these things compile (as I wouldn't expect them to)
//c.StringCollection = { "test1", "test2" };
//c.StringCollection = new Collection<string>();
// 'test1', 'test2', 'test3' is output
foreach (string s in c.StringCollection) Console.WriteLine(s);
}
}
}
This:
MyClass c = new MyClass
{
StringCollection = { "test2", "test3" }
};
is translated into this:
MyClass tmp = new MyClass();
tmp.StringCollection.Add("test2");
tmp.StringCollection.Add("test3");
MyClass c = tmp;
It's never trying to call a setter - it's just calling Add on the results of calling the getter. Note that it's also not clearing the original collection either.
This is described in more detail in section 7.6.10.3 of the C# 4 spec.
EDIT: Just as a point of interest, I was slightly surprised that it calls the getter twice. I expected it to call the getter once, and then call Add twice... the spec includes an example which demonstrates that.
You aren't calling the setter; you are essentially calling c.StringCollection.Add(...) each time (for "test2" and "test3") - it is a collection initializer. For it to be the property assignment, it would be:
// this WON'T work, as we can't assign to the property (no setter)
MyClass c = new MyClass
{
StringCollection = new StringCollection { "test2", "test3" }
};
I think that, beeing read only, you can't do
c.StringCollection = new List<string>();
But you can assign items to list...
Am I wrong?
The StringCollection property doesn't have a setter so unless you add one you cannot modify its value.