i was wandering if there is a way to pass an array to a function that is used on its members( kind of like how you pass the "this" parameter to object).
instead of this:
void public foo(A[] arr){}
void main(){
arr[i].foo(arr);
}
this:
void public foo(A[] arr){}
void main(){
arr[i].foo();
}
edit: arr is array of A, foo belongs to A
sorry for bad explanation first question.
So... if I understand correctly. You want to call an item in the array, with a reference to the array.
But you don't want to pass that reference to the array?
I can only think of a working solution where you make a new class that encapsulates the array[] and create an add method, that upon adding handles the reference binding. (so passing a ref of itself to the added object). So that the items in the array hold a reference to the array.
or maybe you can do some nifty stuff using indexers:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/
Hope this helps!
Related
Starting in C++11, one can write something like
#include <vector>
#include <string>
struct S
{
S(int x, const std::string& s)
: x(x)
, s(s)
{
}
int x;
std::string s;
};
// ...
std::vector<S> v;
// add new object to the vector v
// only parameters of added object's constructor are passed to the function
v.emplace_back(1, "t");
Is there any C# analogue of C++ functions like emplace or emplace_back for container classes (System.Collections.Generic.List)?
Update:
In C# similar code might be written as list.EmplaceBack(1, "t"); instead of list.Add(new S(1, "t"));. It would be nice not to remember a class name and write new ClassName in such situations every time.
In general there is nothing similar in C#, and its need is much less than in C++.
In C# when you have a List<SomeReferenceType> what you really have is a List<ReferenceToSomeType>, so a list of references, with the size of each element of 4 or 8 bytes (see How big is an object reference in .NET?). Copying a reference doesn't cause the underlying object to be duplicated, so it is very fast (you are copying around 4 or 8 bytes, and the processor is optimized for this operation, because that is the size of the native pointer of the processor). So when you someList.Add(someReference) what you are doing is adding a reference to your List<>.
In C++ when you have a std::vector<SomeType> what you have is a vector of SomeType, with the size of each element equal to sizeof(SomeType). Inserting a new element in std::vector<> will cause the element you are inserting to be duplicated (cloned, copied... choose a verb you like). This is an expensive operation.
Quite often the pattern you use is that you create an object just to insert it into a std::vector<>. To optimize this operation in C++11 they added two ways to do it: the std::vector<>::emplace method and support by the std::vector<> of the move semantic. The difference is that the move semantic must be supported by the SomeType type (you need a move constructor with the noexcept specifier), while every type supports the emplace (that in the end simply used placement constructor).
You can a bit improve #Boo variant with extenstion.
You can create object instance with Activator.CreateInstance so it make solution more generic.
public static class ListExtension
{
public static void Emplace<S>(this IList<S> list, params object[] parameters)
{
list.Add((S)Activator.CreateInstance(typeof(S), parameters));
}
}
Note: not checked type and count parameters, so if you do something wrong, you get errors just in run-time
in c# you can use extension method to achive what you want
public static class ListExtension
{
public static void Emplace(this IList<S> list, int x, string s)
{
list.Add(new S(x, s));
}
}
then use it like this
myList.Emplace(1,"t");
It seems you have following problems:
It's longer to type by "new S". But "add" is shorter than "emplace". Type is added for you by intellisense (simply press Enter after typing "new "):
You are afraid to write a wrong type. Well you can't with List<T>. Intellisense will help you to type and compiler will not allow wrong type to be added at compile time anyway.
Performance: see #Xanatos answer.
list.Add(new S(1, "t")); is perfectly fine to use.
Conclusion: we don't need emplace in C#.
Yes, I know this has been discussed many times before, and I read all the posts and comments regarding this question, but still can't seem to understand something.
One of the options that MSDN offers to solve this violation, is by returning a collection (or an interface which is implemented by a collection) when accessing the property, however clearly it does not solve the problem because most collections are not immutable and can also be changed.
Another possibility I've seen in the answers and comments to this question is to encapsulate the array with a ReadOnlyCollection and return it or a base interface of it(like IReadOnlyCollection), but I don't understand how this solves the performance issue.
If at any time the property is referenced it needs to allocate memory for a new ReadOnlyCollection that encapsulates the array, so what is the difference (in a manner of performance issues, not editing the array/collection) than simply returning a copy of the original array?
Moreover, ReadOnlyCollection has only one constructor with IList argument so there's a need to wrap the array with a list prior to creating it.
If I intentionally want to work with an array inside my class (not as immutable collection), is the performance better when I allocate new memory for a ReadOnlyCollection and encapsulate my array with it instead of returning a copy of the array?
Please clarify this.
If at any time the property is referenced it needs to allocate memory for a new ReadOnlyCollection that encapsulates the array, so what is the difference (in a manner of performance issues, not editing the array/collection) than simply returning a copy of the original array?
A ReadOnlyCollection<T> wraps a collection - it doesn't copy the collection.
Consider:
public class Foo
{
private readonly int[] array; // Initialized in constructor
public IReadOnlyList<int> Array => array.ToArray(); // Copy
public IReadOnlyList<int> Wrapper => new ReadOnlyCollection<int>(array); // Wrap
}
Imagine your array contains a million entries. Consider the amount of work that the Array property has to do - it's got to take a copy of all million entries. Consider the amount of work that the Wrapper property has to do - it's got to create an object which just contains a reference.
Additionally, if you don't mind a small extra memory hit, you can do it once instead:
public class Foo
{
private readonly int[] array; // Initialized in constructor
private readonly IReadOnlyList<int> Wrapper { get; }
public Foo(...)
{
array = ...;
Wrapper = new ReadOnlyCollection<int>(array);
}
}
Now accessing the Wrapper property doesn't involve any allocation at all - it doesn't matter if all callers see the same wrapper, because they can't mutate it.
You have no need to copy an array, just return it as IReadOnlyCollection<T>:
public class MyClass {
private int[] myArray = ...
public IReadOnlyCollection<int> MyArray {
get {
return myArray;
}
}
}
public Tiles[,] tiles;
Is a global variable, an array, I dare say, the size of which is yet to be discovered. That's why I wish to initialize it inside a function. Alas, after the function is done, so is the variable. How doth one fix that?
If you wrote something like this:
public void Init()
{
tiles = new Tiles[2, 5];
}
The instantiated array still exists. Because it was stored in the tiles variable, which is in the class scope, it's lifetime is that of the object. Thus, you have nothing to worry about. Subsequently accessing the tiles field (should have been a property...) will use the object created in Init.
As an aside, that variable is not global, it is scoped to the class. Aside from statics, there is no such thing as a "global" variable in C# (and even static members are still scoped to their class, which does have a global instance).
Note
Jon Skeet's answer indicates excellent practice for initializing variables, among other things. I am primarily trying to address the misunderstanding of variable scope/lifetime in this answer.
Sounds like you just want:
private readonly Tile[,] tiles = InitializeTileArray();
...
private static readonly Tile[,] InitializeTileArray()
{
Tile[,] array = ...;
// Whatever you want here
return array;
}
Note that the method has to be static - you can't call an instance method from a field initializer. If you need to do that, you need to put the call into your constructor instead.
Note that I've made the field itself private - and readonly, which may not be appropriate for you. I would recommend always (or at least nearly always) using private fields - you can expose the data via properties and indexers.
here is the situation: I want to call a method from a C++ module, and pass an array to it:
x.Method(array, ...)
x is a C# object. I would suppose that I could change the array and fill it with my own data - but it seems not be the case (?)
How should I pass the array by reference and change its content in the method?
Thank you in advance,
cheers.
Yes, if you want to alter the array beyond just altering its elements (i.e. adding or removing elements) then you have to pass it by reference. The C# declaration would be:
public void Method(ref Mumble[] arg)
Which isn't great syntax. The garbage collector makes it easy to return an array as the function return value:
public Mumble[] Method(Mumble[] input)
But consider a List<Mumble> instead.
You don't need to pass the array by reference. Array is a reference type, so if you pass the array to the method, you're actually passing a reference to it. The method can change the content of the array pointed by the reference, but cannot change the reference itself (i.e. it can't make it point to a different array). If you were passing the array by reference, the method would be able to change the reference to the array, but that's probably not what you're looking for if you just want to fill an existing array.
I suggest you have a look at this article for more details
I'm being passed an object that returns "System.Byte[*]" when converted to string. This apparently isn't a standard one dimensional array of Byte objects ("System.Byte[]"), so what is it?
That's probably a single-dimensional array with a non-zero base.
Here's an example of how to create one:
using System;
class Test
{
static void Main()
{
Array nonZeroBase = Array.CreateInstance
(typeof(byte), new int[]{1}, new int[]{2});
Console.WriteLine(nonZeroBase); // Prints byte[*]
}
}
In CLR terminology this is called an array (rectangular arrays are also arrays) where single-dimensional, zero-based arrays are called vectors. (A multi-dimensional array would be printed as byte[,] though.)
You may be interested in this blog post which Marc Gravell posted just morning...
There is no ...[*] type in c# as far as I remember. Maybe you can find the API documentation for that library, that will show you what the type is really. Even if you don't have that, Visual Studio should show you the type when you try autocompletion on the method returning the object.