Passing array to method in C# - c#

I guess it's rather stupid question.
I want to pass an array argument to method by value, not by link, i.e. I want to make a copy of object to prevent changing of argument inside the method.
Thanks in advance.

If your method acts destructively on its parameter's contents, simply make a copy of the array inside the method.
This is as simple as
var copy = parameter.ToArray();
if you are using LINQ, otherwise it can also be done easily with Array.Copy.
This is much better than copying before calling the method (as you mention in the question), because you can always forget to do that. Copying inside the method leaves no possibility of error.

Arrays are reference types. You can't have them automatically be cloned when passed to a method.
You have to make a clone manually and pass the resulting array to the method:
int[] array = ...
MyMethod((int[])array.Clone());
Note that this is an O(n) operation can can be quite slow for large arrays or many repeated calls.

There is no way to do this in C#. You will need to copy the array yourself, either inside the method, or on the calling side:
int[] array = GetIntArray();
CallSomeMethod(array.ToArray()); // ToArray() makes a copy of the input...

My understanding of the question in the OP is the poster is looking for a way to pass a reference type by value. I found this example:
class PassingRefByVal
{
static void Change(int[] arr)
{
//arr[0]=888; // This change affects the original element.
arr = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
Console.WriteLine("Inside the method, the first element is: {0}", arr[0]);
}
public static void Main()
{
int[] myArray = {1,4,5};
Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", myArray [0]);
Change(myArray);
Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", myArray [0]);
Console.ReadLine();
}
}
here: http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx
Hope this is what you're looking for.

Related

When I append something to my array it doesn't add anything to the list

basically I'm trying to append something to an array, but for some reason in wont even work.
(gObject is a thing with a name and a value)
public gObject[] OBJECTS = {};
public void RegisterObjectToRender(gObject reg)
{
OBJECTS.Append<gObject>(reg);
for (int ri = 0; ri < OBJECTS.Length; ri++)
{
Console.WriteLine(OBJECTS[ri].Name);
}
}
I hope everyone who is reading this is having a good day btw
Arrays are fixed size, always. If you want a list: use a list, i.e. use List<Your type> instead of an array. A list has an Add method.
I'm guessing the Append method here is a local extension method that only exists in your code (that isn't a normal API). I'm also guessing that it calls Array.Resize internally, but: that creates a new and different array - it doesn't change the existing array. So if you use that, you'd need to swap the underlying reference afterwards, too - to the new array reference. However, don't do that: Array.Resize is incredibly inefficient, as it allocates a new array every append (contrast List<T> which keeps an oversized backing array, and tracks the count separately, only increasing the underlying array occasionally).
Append returns a new IEnumerable. It does not add to the OBJECTS, but essentially returns a new list. You have to capture the result of Append and use that: var extendedList = OBJECTS.Append(reg).
A better way is to use a list and use Add instead of Append. It is faster and cleaner.

C# : Changing copy of array changes array itself

I have a very basic question in C#. So I have an array of int called m_permutation (property of a class), and in a method of the class I have the following code:
int[] newPermutation = new int[m_permutation.Length];
newPermutation = m_permutation;
newPermutation[0] = 5;
I am confused as to why m_permutation is also changed in this code, and how can I fix it ?
I understand that I can initialize newPermutation via a loop for, to get the same values of m_permutation, and that fixes it. However, can somebody explain why this happens, and what is the best fix ?
Thank you,
Bogdan
There's some good, and some bad, about your expectations for your code.
Let's go through what your code is actually doing:
int[] newPermutation = new int[m_permutation.Length];
This will declare a new variable, newPermutation, to be an array of ints, and then construct a new int array containing m_permutation.Length elements.
So far so good.
The next line, not so much:
newPermutation = m_permutation;
This line will actually replace the reference in your array variable newPermutation to, after the assignment, refer to the same array as m_permutation.
Let's consider what an array variable actually is.
When you do this:
int[] x = new int[5];
Then you're doing a couple of things:
You're declaring a variable, x
You're constructing a new object containing the int array
You're assigning the variable, x to refer to this object
After the 2nd line:
newPermutation = m_permutation;
you're essentially saying this:
OK, you know that array we just constructed? Forget that
Let's now refer to this other array, the one that the variable m_permutation is also referring to.
So when this line executes:
newPermutation[0] = 5;
You're essentially saying: The array that newPermutation is now referring to, its first element should now have the value 5.
Since newPermutation at this point refers to the same array as m_permutation, it appears that you're modifying an additional array but in reality you only have one array. You do, however, have two variables referring to the same array.
I recommend you read my answer here regarding pointers since this is relevant.
However, there is an easy fix to your problem.
You can ask for a copy of the array, instead of a reference to the original one.
Simply change your code to this:
int[] newPermutation = m_permutation.ToArray();
The .ToArray() method is guaranteed to return a new array, so this won't be shared with the original.
Bear in mind, however, that if you do this with anything more complex than an int, such as an object, you're only getting copies of the object references, not the objects themselves. You can get back to Stack Overflow with new questions when/if you get to this point.
Because they both reference the same object in memory.
You can use,
Array.Copy(m_permutation, newPermutation,m_permutation.Length );

How to use existing method instead of lambda when it's not static?

This must be a duplicate but i haven't found it. I've found this question which is related since it answers why it's recommended to use a method group instead of a lambda.
But how do i use an existing method group instead of a lambda if the method is not in the current class and the method is not static?
Say i have a list of ints which i want to convert to strings, i can use List.ConvertAll, but i need to pass a Converter<int, string> to it:
List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(i => i.ToString());
This works, but it creates an unnecessary anonymous method with the lambda. So if Int32.ToString would be static and would take an int i could write:
List<string> strings = ints.ConvertAll<string>(Int32.ToString);
But that doesn't compile - of course. So how can i use a method group anyway?
If i'd create an instance method like this
string FooInt(int foo)
{
return foo.ToString();
}
i could use strings = ints.ConvertAll<string>(FooInt);, but that is not what i want. I don't want to create a new method just to be able to use an existing.
There is an static method in the framework, that can be used to convert any integrated data type into a string, namely Convert.ToString:
List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(Convert.ToString);
Since the signature of Convert.ToString is also known, you can even eliminate the explicit target type parameter:
var strings = ints.ConvertAll(Convert.ToString);
This works. However, I'd also prefer the lambda-expression, even if ReSharper tells you something different. ReSharper sometimes optimizes too much imho. It prevents developers from thinking about their code, especially in the aspect of readability.
Update
Based on Tim's comment, I will try to explain the difference between lambda and static method group calls in this particular case. Therefor, I first took a look into the mscorlib disassembly to figure out, how int-to-string conversion exactly works. The Int32.ToString method calls an external method within the Number-class of the System namespace:
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), SecuritySafeCritical]
public string ToString(IFormatProvider provider)
{
return Number.FormatInt32(this, null, NumberFormatInfo.GetInstance(provider));
}
The static Convert.ToString member does nothing else than calling ToString on the parameter:
[__DynamicallyInvokable]
public static string ToString(int value)
{
return value.ToString(CultureInfo.CurrentCulture);
}
Technically there would be no difference, if you'd write your own static member or extension, like you did in your question. So what's the difference between those two lines?
ints.ConvertAll<string>(i => i.ToString());
ints.ConvertAll(Convert.ToString);
Also - technically - there is no difference. The first example create's an anonymous method, that returns a string and accepts an integer. Using the integer's instance, it calls it's member ToString. The second one does the same, with the exception that the method is not anonymous, but an integrated member of the framework.
The only difference is that the second line is shorter and saves the compiler a few operations.
But why can't you call the non-static ToString directly?
Let's take a look into the ConvertAll-method of List:
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
if (converter == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
}
List<TOutput> list = new List<TOutput>(this._size);
for (int i = 0; i < this._size; i++)
{
list._items[i] = converter(this._items[i]);
}
list._size = this._size;
return list;
}
The list iteraterates over each item, calls the converter with the item as an argument and copys the result into a new list which it returns in the end.
So the only relation here is your converter that get's called explicitly. If you could pass Int32.ToString to the method, the compiler would have to decide to call this._items[i].ToString() within the loop. In this specific case it would work, but that's "too much intelligence" for the compiler. The type system does not support such code conversions. Instead the converter is an object, describing a method that can be called from the scope of the callee. Either this is an existing static method, like Convert.ToString, or an anonymous expression, like your lambda.
What causes the differences in your benchmark results?
That's hard to guess. I can imagine two factors:
Evaluating lambdas may result in runtime-overhead.
Framework calls may be optimized.
The last point especially means, that the JITer is able to inline the call which results in a better performance. However, those are just assumptions of mine. If anyone could clarify this, I'd appreciate it! :)
You hit the nail on the head yourself:
This works, but it creates an unnecessary anonymous method with the
lambda.
You can't do what you're asking for because there is no appropriate method group that you can use so the anonymous method is necessary. It works in that other case because the implicit range variable is passed to the delegate created by the method group. In your case, you need the method to be called on the range variable. It's a completely different scenario.

ERROR: use of unassigned local variable (for string array)

I am reading connection strings from my App.config file and for that i have following code.
try
{
string[] dbnames;
int counter = 0;
foreach (ConnectionStringSettings connSettings in ConfigurationManager.ConnectionStrings)
{
dbnames[counter] = connSettings.Name;
counter++;
}
return dbnames;
}
catch
{
throw;
}
this code giving me error use of unassigned local variable for dbnames. i will have multiple connection strings in my App.config. They can be none,1,2 and so on. Depending on the needs. so i cant statically assign the dbname size. Because there can be a scenario if they exceed the value of assigned size. eg. if i assign it a size of 5, and what if i get 6th connection string. and if i have 1, then remaining 4 will be a memory wastage.
If i am wrong then let me know.
Thanks.
Use this while initializing the array.
string[] dbnames = new string[ConfigurationManager.ConnectionStrings.Count];
OR use List<string>
You can't resize a System.Array dynamically like that.
Fortunately, there's no reason to do so. Use a different type of collection, like a List<T> instead. (Make sure you've added a using declaration for the System.Collections.Generic namespace!)
Like an array, a List<T> allows you to access the elements in the list by index, but it's also dynamically resizable at run-time, which fulfills the requirements in your question. And of course, since it's a generic method, it has the additional advantage (as compared to some of your other choices) of being strongly-typed. Since you're working with string types, you would use List<string>.
EDIT: There's absolutely no need for that empty try/catch block. Why catch an exception if you're just going to immediately rethow it? Just let it bubble up. In general, you shouldn't catch exceptions unless and only unless you can fix their immediate cause.
You're declaring dbnames as a string array, but not defining it's size.
You'll need something like:
string[] dbames = new string[4];
where "4" is the length of your array.
If, however, you need a variable length you should use List<string>. In this case you can then add to it as necessary.
As others have said, you could just use a List<string>. I would use LINQ to do all of this though, if you're using .NET 3.5 or higher:
return ConfigurationManager.ConnectionStrings
.Cast<ConnectionStringSettings>()
.Select(setting => setting.Name)
.ToArray(); // Or ToList
No need for a foreach loop (in your code - obviously it's there somewher :)
You can easily decide whether to return a list, an array, or simply IEnumerable<string>
No need for try/catch
declare it after class
e.g
i am also writing code and i used to always encounter this problem
public class ABC{
string[] array;
ABC()
{
}
//your_function_logics
}

Does Array.ToArray<>() return the original array if it is the same type?

I deal with a framework on a daily basis where we sometimes provide methods that accept IEnumerable<MyBusinessObject> as a parameter in order to show user interfaces, perform calculations etc.
If I pass in an array of MyBusinessObject like so:
MyBusinessObject[] myArray = new MyBusinessObject { obj1, obj2, ..., objN };
frameworkClass.MyMethod(myArray);
....
public class FrameworkClass
{
public void MyMethod(IEnumerable<MyBusinessObject> objs)
{
// Other code that uses the enumerable
MyBusinessObject[] objectArray = objs.ToArray();
// More code that uses the enumerable
}
}
Does the line objs.ToArray() simply resolve the IEnumerable<MyBusinessObject> back to the original array, or does it copy it to a whole new array, ready for use?
No, you will always get a new copy of the array, though the objects in it aren't copies, they are the same references as in the original array.
It would be very inconsistent for changes to the returned array to sometimes affect the source and sometimes not. ToList works the same way for the same reason.
You can check source code (as of 2015) if you need to review details: Enumerable.ToArray which in turn creates copy of elements (optimized for ICollection and hence Array[], but still making copy) with internal Buffer class.
You will get a new copy of the array if there is one or more element in it. For empty arrays, you might get the same array back, at least in .NET 5:
Console.WriteLine(Object.ReferenceEquals(Array.Empty<string>(), Array.Empty<string>().ToArray()));
This returns true.

Categories