What does the new[] {string} syntax mean? - c#

I'm studying a book with Membership topic in ASP.NET MVC and I found syntax, I cannot trace (and not explained in the book), which is:
new[] {"string"}
like in:
Roles.AddUsersToRoles(new[] {userName}, new[] {roleName});
Per MDSN library I see Roles.AddUsersToRoles method takes two string arrays as arguments, so likely this is a shorthand or would this have some additional functionality?

It is Implicitly Typed Arrays syntax.
You can create an implicitly-typed array in which the type of the
array instance is inferred from the elements specified in the array
initializer.
This
string[] stringArray = new[] {"string"};
is same as :
string[] stringArray = new string[] {"string"};
Other thing to note, the method Roles.AddUsersToRoles accepts two parameters of string type array (and not a string).
public static void AddUsersToRoles(
string[] usernames,
string[] roleNames
)

new string[1] { "string" }
You can omit the array size because the compiler can count the number of elements for you:
new string[ ] { "string" }
You can also omit the array element type because the compiler can infer it from the values provided:
new [ ] { "string" }
But do not get this mixed up with initializers for anonymous types. These do not have the angle brackets [] after new:
new { StringProperty = "string" }
or:
// string StringProperty;
new { StringProperty }

Related

Optional Multidimensional Arrays as Arguments in C#

I want to declare a function that has 1 required argument and 4 optional 2D array arguments, how do i do so? I know to make an argument optional, we should place a value in it during function creation.
I also saw what I did below is wrong and has a "Array initializers can only be used in a variable or field initializer. Try using a new expression instead." Error
private String communicateToServer(String serverHostname,
String[,] disk = new string[] {{"dummy","dummy"}},
String[,] hdd= new string[] {{"dummy","dummy"}}
String[,] nic= new string[] {{"dummy","dummy"}}
String[,] disk = new string[] {{"dummy","dummy"}}
)
It's not possible to do this directly but you can get a similar effect by doing the following pattern
private String communicateToServer(String serverHostname,
String[,] disk = null,
String[,] hdd= null,
String[,] nic= null) {
disk = disk ?? new string[] {{"dummy","dummy"}},
hdd= hdd ?? new string[] {{"dummy","dummy"}}
nic= nic ?? new string[] {{"dummy","dummy"}}
...
}
Essentially use null as the default and if null is the value convert to the actual default. This does mean that an explicit null being passed will be interpreted as the default value though.

c# place string into an array

This could be very easy, but how can I place or convert a string into an array?
The code that I have, is the following:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string one;
string[] two;
one = "Juan";
two = {one}; // here is the error
HttpContext.Current.Response.Write(two);
}
}
And the error is the following:
Compiler Error Message: CS0029: Cannot implicitly convert type 'string' to 'string[]'
Thanks for you help!
Replace this:
two = {one}; // here is the error
With
two = new[] { one };
OR
two = new string[] { one };
The reason you are getting the error is clear from the error message.
See: Object and Collection Initializers (C# Programming Guide)
Later when you are doing Response.Write, you will get System.String[] as output, since two is an array. I guess you need all array elements separated by some delimiter. You can try:
HttpContext.Current.Response.Write(string.Join(",", two));
Which will produce all the elements in the array separated by comma
It looks like you're trying to use initialization syntax for an assignment. This should work:
two = new string[] {one};
or just
two = new [] {one};
since the compiler will infer that you want a string[]
I think you'll also be surprised what Response.Write(two); produces...
You're using the static initializer syntax to try and add an item to your array. That doesn't work. You can use similar syntax to allocate a new array with the value one - two = new string[] { one }; - or you can allocate the array then add elements through assignment like;
string[] two = new string[10];
two[0] = one; // assign value one to index 0
If you do it like this you have to do some bounds checking for example the following will throw an IndexOutOfRangeException at runtime;
string[] two = new string[10];
int x = 12;
two[x] = one; // index out of range, must ensure x < two.Length before trying to assign to two[x]
That syntax ({one}) is only valid if you declare the array variable in the same line. So, this works:
string one;
one = "Juan";
string[] two = {one};
A more common way to initialize an array, which works in more places, is to use the new keyword, and optionally have the type be inferred, e.g.
string one;
string[] two;
one = "Juan";
// type is inferrable, since the compiler knows one is a string
two = new[] {one};
// or, explicitly specify the type
two = new string[] {one};
I usually declare and initialize on the same line, and use var to infer the type, so I'd probably write:
var one = "Juan";
var two = new[] { one };

How to create 2 multidimensional string array (remove blank strings)?

var movieNext = new string[,]
{
{ "superhero", "action", "waltdisney", "bat"},
{"superhero", "action", "marvel",""},
{"history", "action", "malay", "" },
{"malay", "novel", "", ""},
{"history", "bat", "", ""}
};
The above code is a multidimensional array, which stores a sequence of movie's keyword. Is there a way to implement this without having to put the blank strings in the array initialization?
For example you can see in the above code, I have to put the blank string "" to fill up the array.
You could use a jagged array instead.
string[][] movieNext = new string[][] { { etc... } }.
You can consider C# jagged array (though they are different from multi-dimensional arrays).
string[][] movieNext = {
new [] { "superhero", "action", "waltdisney", "bat"},
new [] {"superhero", "action", "marvel"}, <and so on>
};
If you want to stick with multi-dimensional arrays, you have to initialize the values individually. If you don't provide any string value for any of the index (i,j) by default it will be null.
I suggest never to use two-dimensional arrays. They have practically no support in the API (you'll be hard pressed to find a method that accepts a two-dimensional array as a parameter), and cannot be cast to IEnumerable<T> or similar well-supported interface. As such, you can really use them only in the most local of scopes.
Instead, I suggest you use something castable to IEnumerable<IEnumerable<string>>. Oh, another tip. Check this out. Specifically,
To initialize a Dictionary, or any collection whose Add method takes multiple parameters, enclose each set of parameters in braces as shown in the following example.
Thus, the following will work:
class Program
{
static void Main(string[] args)
{
var d = new ManyList()
{
{"Hi", "Good", "People", "None", "Other"}
{"Maybe", "Someone", "Else", "Whatever"}
};
Console.Read();
}
}
class ManyList : List<string>
{
public void Add(params string[] strs)
{
Console.WriteLine(string.Join(", ", strs));
}
}
This might help you clean up your syntax a bit.

string.Format fails at runtime with array of integers

Consider string.Format() whose parameters are a string and, among others in the overload list, an object[] or many objects.
This statement succeeds:
string foo = string.Format("{0} {1}", 5, 6);
as does this:
object[] myObjs = new object[] {8,9};
string baz = string.Format("{0} and {1}", myObjs;
as does an array of strings:
string[] myStrings = new string[] {"abc", "xyz"};
string baz = string.Format("{0} {1}", myStrings);
It seems that the integers, when specified individually, can be boxed or coerced to type object, which in turn is coerced to a string.
This statement fails at runtime.
int[] myInts = new int[] {8,9};
string bar = string.Format("{0} and {1}", myInts);
Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
Why doesn't or can't the int array be coerced or boxed to an object[] or string[]?
Out of a small bit of curiosity, why doesn't the compiler catch this?
The call fails with the same reason the following will also fail:
string foo = string.Format("{0} {1}", 5);
You are specifying two arguments in the format but only specifying one object.
The compiler does not catch it because int[] is passed as an object which is a perfectly valid argument for the function.
Also note that array covariance does not work with value types so you cannot do:
object[] myInts = new int[] {8,9};
However you can get away with:
object[] myInts = new string[] { "8", "9" };
string bar = string.Format("{0} {1}", myInts);
which would work because you would be using the String.Format overload that accepts an object[].
Your call gets translated into this:
string foo = string.Format("{0} {1}", myInts.ToString());
which results in this string:
string foo = "System.Int32[] {1}";
So as the {1} doesn't have a parameter, it throws an exception
I think the concept you are having an issue with is why int[] isn't cast to object[]. Here's an example that shows why that would be bad
int[] myInts = new int[]{8,9};
object[] myObjs = (object[])myInts;
myObjs[0] = new object();
The problem is that we just added an object into a int array.
So what happens in your code is that myInts is cast to object and you don't have a second argument to fill in the {1}
Short way to make it work (not the most optimal though):
int[] myInts = new int[] { 8, 9 };
string[] myStrings = Array.ConvertAll(myInts, x => x.ToString());
// or using LINQ
// string[] myStrings = myInts.Select(x => x.ToString()).ToArray();
bar = string.Format("{0} and {1}", myStrings);
This is quite an old question, but I recently got the same issue. And I haven't seen an answer that works for me, so I'll share the solution I found.
Why doesn't or can't the int array be coerced or boxed to an object[] or string[]? Why it isn't boxed, I don't know. But it can be boxed explicitly, see solution below.
Why doesn't the compiler catch this? Because the compiler misinterprets the situation: The type isn't exactly an object array, so it doesn't know what to do with it and decides to perform a .ToString() on the int array, which returns one single parameter containing the type name rather than the parameter list itself. It doesn't do that with a string array, because the target type is already a string - but with any other kind of array the same issue happens (for example bool[]). Consider var arr1 = new int[]{1,2}; with string.Format("{0}", arr1): As long as you have only {0} in the format string, you get only the type name "System.Int32[]" back (and no exception occurs). If you have more placeholders, e.g. string.Format("{0}{1}", arr1), then the exception occurs - because arr1 is misinterpreted as one parameter - and for the compiler, a 2nd one is missing. But what I think is a conceptional bug is that you can't convert arr1, i.e. if you try to do (object[])arr1- you're getting:
CS0030 Cannot convert type 'int[]' to 'object[]'
Solution:
Filling in each element of the int array is not a solution that works for me, because in my project I am creating a format template string dynamically during runtime containing the {0}...{n} - hence I need to pass an array to String.Format.
So I found the following workaround. I created a generic helper function (which of course could be an extension method too if you prefer):
// converts any array to object[] and avoids FormatException
object[] Convert<T>(T[] arr)
{
var obj = new List<object>();
foreach (var item in arr)
{
obj.Add((object)item);
}
return obj.ToArray();
}
Now if you try that in the example below which is showing up the FormatException:
// FormatException: Index (zero based) must be greater than or equal to zero
// and less than the size of the argument list
var arr1 = (new int[] { 1, 2 });
string.Format("{0}{1}{0}{1}", arr1).Dump();
Fix: Use Convert(arr1) as 2nd parameter for string.Format(...) as shown below:
// Workaround: This shows 1212, as expected
var arr1 = (new int[] { 1, 2 });
string.Format("{0}{1}{0}{1}", Convert(arr1)).Dump();
Try example as DotNetFiddle
Conclusion:
As it seems, the .NET runtime really misinterprets the parameter by applying a .ToString() to it, if it is not already of type object[]. The Convert method gives the runtime no other choice than to do it the right way, because it returns the expected type. I found that an explicit type conversion did not work, hence the helper function was needed.
Note: If you invoke the method many times in a loop and you're concerned about speed, you could also convert everything to a string array which is probably most efficient:
// converts any array to string[] and avoids FormatException
string[] ConvertStr<T>(T[] arr)
{
var strArr = new string[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
strArr[i]=arr[i].ToString();
}
return strArr;
}
This is working as well. To convert from a different datatype, such as a dictionary, you can simply use
string[] Convert<K,V>(Dictionary<K,V> coll)
{
return ConvertStr<V>(coll.Values.ToArray());
}
Update: With string interpolation, another short way to solve it is:
var baz = string.Format("{0} and {1}", myInts.Select(s => $"{s}").ToArray());
Your string.Format is expecting 2 arguments ({0} and {1}). You are only supplying 1 argument (the int[]). You need something more like this:
string bar = string.Format("{0} and {1}", myInts[0], myInts[1]);
The compiler does not notice the problem because the format string is evaluated at runtime. IE The compiler doesn't know that {0} and {1} mean there should be 2 arguments.
This works:
string bar = string.Format("{0} and {1}", myInts[0], myInts[1]);
The compiler doesn't catch it because it doesn't evaluate your format string.
The example you gave up top doesn't match what you're trying to do down below... you provided two {} and two arguments, but in the bottom one you only provided one argument.

Value assignment in C#

Without initialization how is it possible to assign values to arrays?
string[] s={"all","in","all"};
I mean why did not the compile show error?.Normally we need to
initialize ,before assign values.
It's just syntactic sugar.
This:
string[] s = {"all","in","all"};
is compiled to the same code as:
string[] tmp = new string[3];
tmp[0] = "all";
tmp[1] = "in";
tmp[2] = "all";
string[] s = tmp;
Note that the array reference is not assigned to s until all the elements have been assigned. That isn't important in this particular case where we're declaring a new variable, but it would make a different in this situation:
string[] s = { "first", "second" };
s = new string[] { s[1], s[0] };
The same is true for object and collection initializers - the variable is only assigned at the end.
It is possible to declare an array variable without initialization.
Check this out
http://msdn.microsoft.com/en-us/library/0a7fscd0%28VS.71%29.aspx
You aren't "assigning a value to array". You are initializing a variable of type "reference to array". The value with which you initialize it is a reference to an array which was created by the use of short array initializer syntax {...}. While it is only permissible in initializer of variables of array type, it is exactly equivalent to new T[] { ... }, where T is deduced from type of variable.
I think you want to know why
string[] s={"all","in","all"};
works when you would expect to be required to initialize the array first like this :
string[] s = new string[];
or
string[] s = new string[] {"all","in","all"};
The answer is just compiler magic. The compiler knows based on the initialization how big to make the array so it just does it behind the scenes for you. Much like the var keyword, the point is to limit the amount of redundant information you're required to type.
The {"all","in","all"} part is the initialization. the new string[] part can be omitted because the curly braces and string are short hand notation. Take a look at MSDN on Single Dimension Arrays.
string[] s = new string[] { "all","in","all"};
and its shorthand version
string[] s = {"all","in","all"};
are the same thing. See MSDN (Initializing Arrays section) for more detail.
You don't need the new string[] part in C#3 or higher - this works fine
string[] s = { "all","in","all"};
It's just a case of the compiler being a bit smarter and working out what you mean - the back end IL will be the same.
You can do so simply because it is allowed, doing so in two steps is not necessary so this is the shorthand. Consider it sugar.

Categories