I'm using a third party library. One of the methods requires passing an array via ref that will be populated with some info. Here's the definition for the method:
int GetPositionList(ref Array arrayPos)
How do I construct arrayPos so that this method will work? In the library's not so complete documentation it defines the method as such:
long GetPositionList(structSTIPosUpdate() arrayPos)
I've tried this but of course I'm getting errors:
System.Array position_list = new System.Array();
sti_position.GetPositionList(ref position_list);
Any ideas?
This is the Sterling Trader Pro ActiveX API, right? Did you create an Interop dll using tlbimp.exe? The GetPositionList API expects an array which will hold structs of type structSTIPositionUpdate. Normally an out modifier is used if the callee initializes the passed-in data, and ref if the data is to be initialized. According to the meaning of the API the modifier should be out, so that this should work:
structSTIPositionUpdate [] entries = new structSTIPositionUpdate[0]; // or null
num_entries_returned = GetPositionList(ref entries);
Alternatively, try creating an array of these structs which is big enough to hold the expected number of entries, then pass it to the function:
structSTIPositionUpdate [] entries = new structSTIPositionUpdate[100]; // say
num_entries_returned = GetPositionList(entries);
Update: If you are getting type mismatches with System.Array, try
System.Array entries = Array.CreateInstance(typeOf(structSTIPositionUpdate), N);
where N is the number of elements in the array.
To create an instance of an Array you can use the CreateInstance method:
Array a = Array.CreateInstance(typeof(Int32), 10);
GetPositionList(ref a);
The type, dimension and size of the array is something the library author should document. The GetPositionList may be badly designed and simply create a new Array for you essentially meaning that the library author should have used out instead of ref. In that case you can use a null array:
Array a = null;
GetPositionList(ref a);
You can use Array.CreateInstance
This may help you:
http://msdn.microsoft.com/en-us/library/szasx730%28VS.80%29.aspx
...although I don't understand why an object needs to have the "ref" keyword. Objects are passed by reference, so this should work anyway, without making use of the ref keyword. For arrays like int[] or string I understand this...
This works:
Array position_list = new int[]{1, 3, 5, 5,6};
sti_position.GetPositionList(ref position_list);
I also using Sterling Trader API. I use this code:
private structSTIPositionUpdate[] PositionList {
get {
Array arrayPos = null;
_position.GetPositionList(ref arrayPos);
return (structSTIPositionUpdate[]) arrayPos;
}
}
Related
I'm trying to select a random user control within an array list. I get the index of the array but it tells me it cannot simply convert int to UserControl. Anyone knows what I did wrong?
ArrayList notiList = new ArrayList();
int count = 0;
int i;
public MainPage()
{
this.InitializeComponent();
foreach (NotiObject noti in itemsPanel.Children.Where(c => c is NotiObject))
{
notiList.Add(noti);
System.Diagnostics.Debug.WriteLine(noti);
}
i = new Random().Next(0, notiList.Count);
}
void sendNotification()
{
NotiObject randomNoti = notiList.IndexOf(i);
}
As Dai has hinted, ArrayList is a particularly old thing, from back in the days when .net was relatively new and didn't have the incredibly useful feature known as generics.
The manual page for ArrayList says this (my emphasis):
Important
We don't recommend that you use the ArrayList class for new development.
Instead, we recommend that you use the generic List class.
Even the manufacturer is saying "don't use this product"
The big problem with ArrayList is that because it wants to be able to store anything, it holds its contents in an object array
This means you can put two completely unrelated things in next to each other, you have to inspect the type of them if you do, and you always have to cast to turn the object back into what you want
notiList.Add(123); //whoops, that's not a NotiObject
foreach(var o in notiList)
var n = (NotiObject)notiList[0]; //whoops, that's a crash
}
So, working with it is pretty wearisome, particularly the part where you have to cast all the time.. This gets boring very quickly:
object o = "hello";
object p = "world";
object q = (string)o + (string)p;
object r = ((string)q).Substring(3).IndexOf((stribg)p);
r = (int)r + ((int)r)/2;
Storing everything in an object can be done, but look at what a mess it is. You'd have to start putting the type name into the variable name just to help remember that r was an int, and q was a string - Hungarian notation's another relic of the past.
When you put things in an ArrayList, this is what you're doing; storing them in object
So generics were invented and List was invented. A list that can be custom made to store a single type of objects like a string, int or NotiObject
var nums = new List<int>();
nums.Add(123); //works
var notiList = new List<NotiObject>();
notiList.Add(123); //compiler refuses this one
Now I've said all that, it's possible to answer your question. This code doesn't make sense:
NotiObject randomNoti = notiList.IndexOf(i);
i is an integer. IndexOf is a method that finds the numeric index of an item in the list. If the list was "a","b","c" and you asked for IndexOf("b") the result is 1 because b is at the second index, and indexing starts from 0.
IndexOf is not "get me the object at index blahblah", it's "tell me the index of this object blahblah"
The code doesn't make sense because you've passed an integer in and the list stores NotiObject. IndexOf will never find an integer in a list of NotiObject. This was the first mistake. You were allowed to make it because ArrayList stores everything as objects so you're allowed to pass an integer into IndexOf even if there are no integers in the list
IndexOf returns an integer. You cannot assign an integer to a variable of type NotiObject. This is the thing the compiler is complaining about
Even if you form the code correctly, you still have to cast:
NotiObject randomNoti = (NotiObject)notiList[i];
It's all very wearisome and if you persist with ArrayList probably not the last mistake you'll make with it either
If you used a List<NotiObject> you wouldn't have been allowed to pass an integer to IndexOf; the compiler would have stopped you which would hopefully then have made you assess IndexOf in the docs, and see that it's for finding the int index from the object, not the object at int index
You'd write code like:
List<NotiObject> notiList = new List<NotiList>();
...
NotiObject randomNoti = notiList[i];
without the cast. If you want to read more into why there is no cast, check out some introductory articles to generics. In a nutshell generics (any time you see something like <T> or <TBlahBlah>) allow you to specify something like a template code skeleton that the compiler uses to create code for you; code that substitutes the for the kind of object you want to work with. There isn't any casting any more because the compiler will write a whole List class that dedicatedly only works with NotiObjects
I've got a function which takes a ArrayList and loads it with strings along the line of
void func( ref ArrayList data )
{
if( data[0].GetType() == typeof(String) )
data[0] = "Jimmy";
}
In the function that calls func() I am having to create strings to put in the array:
ArrayList data = new ArrayList(1);
string str = "";
data.Add(str);
Is it possible to give the ArrayList the object types without having to create an object of that type? This:
ArrayList data = new ArrayList(1);
string str;
data.Add(str);
Gives a "Use of unassigned local variable 'str'" error.
#James and Guffa: Thanks for the 'stylistic' hints, I'm new to c# and the advice is much appreciated
No, that is not possible. What you want is a reference that points to a string, and that is only possible if it actually points to a string. The fact that the variable that holds the reference is declared as a string reference doesn't matter once you have copied the reference from the variable to the list.
I think that you should rethink the entire concept. I don't know your reason for sending in a list of values and replace them like that, but there has to be a more object oriented way of doing it.
The ArrayList class is practically obsolete, you should use a generic List<T> instead (even if you can't find any other common base class than object).
As you are always sending in a list object to the method and not replacing it with a new list object, you should not use the ref keyword. That's only for when you want to change the reference to the list, not the contents of the list.
You can send two parameters, one ref ArrayList in which members will be assigned and the other an ArrayList and the called function can assign at indexes in data where the type is String
If you are only wanting to keep this type safe then could you not use a List<T> class here instead e.g. List<string>?
What you're trying to do in your method with the above code is to call GetType() on null, which is not possible.
Why not use a generic list List<string> in this case? You can elegantly skip the part of using GetType() to determine the type with this approach:
static void func(List<string> data)
{
if(data.Count > 0)
data[0] = "Jimmy";
}
static void Main(string[] args)
{
List<string> lst = new List<string>(1);
string str = "";
lst.Add(str);
func(lst);
System.Console.WriteLine(lst[0]); //Prints out 'Jimmy'
}
I have the below piece of code which Prefixs a string to the start of each member of a string array. ie. ["a","b","c"] prefixed with "z" becomes ["za","zb","zc"].
private string[] Prefix(string[] a, string b) {
for(int i = 0;i < a.Length;i++) {
a[i] = b + a[i];
}
return a;
}
The function works fine (although if theres a better way to do this, I'm happy to hear it), but I'm having issues when passing parameters.
string[] s1 = new string[] {"a","b"};
string[] s2 = Prefix(s1,"z");
Now as far as I can tell, I'm passing s1 by Value. But when the Prefix function has finished, s2 and s1 have the same value of ["za,"zb"], or s1 has been passed by reference. I was certain you had to explicitly declare this behaviour in c#, and am very confused.
As others have said, the reference is passed by value. That means your s1 reference is copied to a, but they both still refer to the same object in memory. What I would to do fix your code is write it like this:
private IEnumerable<string> Prefix(IEnumerable<string> a, string b) {
return a.Select(s => b + s);
}
.
string[] s1 = new string[] {"a","b"};
string[] s2 = Prefix(s1,"z").ToArray();
This not only fixes your problem, but also allows you to work with Lists and other string collections in addition to simple arrays.
C#, like Java before it, passes everything by value by default.
However, for reference types, that value is a reference. Note that both string and array are reference types.
Here's a better way to do it:
private string[] Prefix(string[] a, string b) {
return a.Select(s => b + s).ToArray();
}
or even:
private IEnumerable<string> Prefix(IEnumerable<string> a, string b) {
return a.Select(s => b + s);
}
You are passing the reference to s1 by value. In other words, your a parameter (when in the Prefix function scope), and your s1 variable, are references to the same array.
strings are immutable
this means that when you append a string to a string you get out a totally new string - its for performance reasons. its cheaper to make a new string that to reallocate the existing array.
hence why it feels like you are working with strings by value
in c# all reference types are passed by reference by default - ie classes creaped on the heap rather than values.
Actually, a reference to s1 was passed by value to Prefix(). While you now have two different references, both s1 and s2 still refer to the same string array, as arrays are reference types in C#.
Passing by value doesn't mean that you can't change things.
Objects are passed by value, but the value is (effectively) a pointer to the object.
Arrays are objects and a pointer to the array gets passed in. If you change the contents of the array in a method, the array will reflect the changes.
This doesn't happen with strings only because strings are immutable - once constructed, their contents can't change.
A reference to the string array is passed by value.
Consequently, the original array reference in the calling method cannot be changed, meaning that a = new string[10] within the Prefix method would have no impact on the s1 reference in the calling method. But the array itself is mutable, and a duplicate reference to the same array is capable of making changes to it in a way that would be visible to any other reference to the same array.
The value of an object is passed. For "reference" objects this is the value of the reference. A clone/copy/duplicate of the underlying data is not made.
To fix the issue observed, simply don't mutate the input array -- instead, create a new output array/object and fill it in appropriately. (If you must use arrays, I would likely use this approach as it's so boringly C-like anyway.)
Alternately, you can clone the input array first (which also creates a new object). Using a clone (which is a shallow copy) in this case is okay because the inner members (strings) are themselves immutable -- even though they are reference types the value of the underlying object can't be changed once created. For nested mutable types, more care may need to be taken.
Here are two methods which can be used to create a shallow copy:
string[] B = (string[])A.Clone();
string[] B = (new List<string>(A)).ToArray();
It's not inclusive.
Personally though, I would use LINQ. Here is a teaser:
return a.Select(x => b + x).ToArray();
I'm trying to get the value of a property that is a single dimensional array via reflection
I tried something like this: (try catches removed for clarity)
string[] fieldOrder;
PropertyInfo fieldOrderColumn;
fieldOrderColumn = targetType.GetProperty("OrderArray");
if (fieldOrderColumn == null)
throw new Exception(targetType.Name + " the OrderArray is null ");
fieldOrder = (string[])fieldOrderColumn.GetValue(targetType, null); //what should I use insted of this?
Clearly the last line is wrong, and is trying to get a non array object, I assumed a
quick google and I'd be on my way, but I'm unable to find it. I don't know the lenght of the array at run time.
Any hints or links or help would be greatly appreciated.
You need to pass an instance of the type into GetValue. If it is a static property, pass null. Currently you are passing the type. I would expect to see (roughly):
Type targetType = obj.GetType();
...[snip]
fieldOrder = (string[])fieldOrderColumn.GetValue(obj, null);
Note that if you aren't sure of the type of array, you can just use Array (instead of string[]), or for single-dimension arrays IList may be useful (and will handle arrays, lists etc):
IList list = (IList)fieldOrderColumn.GetValue(obj, null);
This seems like a basic question, but it's still bugging me.
Why doesn't
MyObject [] myobject = new MyObject [10];
allocate 10 objects? Why do we have to call new on each individual object?
myobject [0] = new MyObject();
:::
myobject [9] = new MyObject();
Or am I just making a silly mistake? :)
As far as I am aware, you arent creating 10 objects in the array, you are creating an array with 10 spaces for objects of type "My Object", null is a perfectly acceptable state for an item within the array though.
You're calling the array constructor, which creates an array, not the object constructor ten times.
What constructor on the element type would you like to call? There's no way to provide any parameters as it is. The only constructors being called implicitly are value types (structs) like integers and doubles.
What if the element constructor fails? It could throw any exception. Should you get an half initialized array, or no array at all? Should the exception bubble or be hidden?
What if the element constructor is just very very slow. Add a Thread.Sleep() and the code that calls you would basically hang. How would you debug that?
And my last thought, why are you even using arrays when there's List<T>? =)
It's because it only allocates references to MyObject, not the object itself. That's the case with every non-primitive type in languages like C# or Java.
You could also use the following declaration style (not particularly useful in the following example, I would recommend a for loop instead)
MyObject[] myObject
= new MyObject[]
{ new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject(),
new MyObject()
};
however, in this case it could be easier to type.
int[] myInts = new int[]{ 10,34,13,43,55,2,0,23,6,23 };
That's exactly how it should be done.
For example:
MyObject[] myObject = new MyObject[10]; // creates 10 null references
for (int i=0;i<myobject.Length;i++)
myobject[i] = new MyObject();
Because all you have created is an array with 10 spaces that will contain your MyObject object instances. When will you put those in and in what state, it's up to you.
Looks like your talking about C# from the syntax.
More or less, in the CLR/.NET framework, an array is an array which contain's object's of type MyObject. Unlike C/C++, where an array is an array of objects of type MyObject.
i.e. C# array's are simply container's, conceptually they are they are distinct from the object's they hold. C/C++ (native memory), your pretty much cheating and forgo'ng the formality of having clear seporation of duties... your array is essentially the object it contains....