.NET Reflection and an array - c#

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);

Related

Cannot compare object from Arraylist to the actual object

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

C#: Why does dynamic help determine type argument for use in generic methods?

I'm working with reflection to create some meta-tests to ensure equality between two instances of the same type.
As such, I'm using a lot of vars and generics.
One thing I've noticed is that with my generic functions, sometimes the Type argument is object (presumably when it can't determine the type) and other times it's the correct type.
Example:
Generic methods
public static RT[] CreateArrayWithNumItems<RT>(RT baseArgument, int numItems)
{
var a = new List<RT>();
for (int i = 0; i < numItems; i++)
a.Add((RT)DataObjectCreator.CreateUninitializedObject(typeof(RT)));
return a.Select(x => (RT)x).ToArray();
} //actual implementation more complex
private static T UnboxObject<T>(T boxedObject)
=> boxedObject;
public static object CreateUninitializedObject(Type typeObject)
=> typeObject == typeof(string) ? "" : FormatterServices.GetUninitializedObject(typeObject);
Use of methods:
var a = Model.GetType();
var unitializedObject = CreateUninitializedObject(a); //returns typed object
var objectArray = CreateArrayWithNumItems(unitializedObject, 1); //returns object array
var uob = UnboxObject(unitializedObject); //returns typed object
var uobObjectArray = CreateArrayWithNumItems(uob, 1); //returns object array
var typedArray = CreateArrayWithNumItems((dynamic) unitializedObject, 1); //returns typed object array
This seems strange to me (a.k.a I'm missing some knowledge), so I have a few questions about it.
Given the same variable, why does UnboxObject return a typed object and CreateArrayWithNumItems return an array of object?
Given the typed object uob why does CreateArrayWithNumItems return an array of object?
Lastly (and most importantly), why does casting to dynamic prior to calling CreateArrayWithNumItems allow the generic method to determine the type?
Without dynamic, the compiler performs all the type evaluations based on static analysis; assuming that CreateUninitializedObject returns object (presumably via FormatterServices), the call to CreateArrayWithNumItems infers the generic type parameters based on that static type, i.e.
var objectArray = CreateArrayWithNumItems(unitializedObject, 1);
becomes
var objectArray = CreateArrayWithNumItems<object>(unitializedObject, 1);
precisely because unitializedObject is object.
With dynamic, the runtime performs the work, but now it has knowledge of the actual object at runtime, so it knows that the type is (whatever Model is). The runtime then constructs something like:
dynamic objectArray = CreateArrayWithNumItems<TheActualType>((TheActualType)unitializedObject, 1);
(how it actually does it is much more complex; it could look for non-generic methods too, for example)
So yes, using dynamic can be a sneaky way to go from reflection (object/Type) code to strongly-typed generic code, but: it has a cost: dynamic involves more work at runtime - additional reflection, and additional runtime IL emit. You also need to be aware that typedArray is now also dynamic (unless you cast it to something else), so everything you do with typedArray becomes dynamic. Increasing costs.

Assigning unassigned string to array

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'
}

How to convert a JavaScript array of doubles to a .NET array of doubles?

What is the best way to convert a JavaScript array of doubles
return [2.145, 1.111, 7.893];
into a .NET array of doubles, when the Javascript array is returned from a webbrowser controls document object
object o = Document.InvokeScript("getMapPanelRegion");
without using strings and parsing?
The object returned is of type __ComObject as it is an array being returned. The array will be a fixed size as I am using this to return three values back to the calling code. My current solution is to return a | deliminated string of the three value, I then split and parse the string to get my three doubles. If possible I would like to not have to use the string manipulation as this feels like a hack.
From MSDN (HtmlDocument.InvokeScript Method):
The underlying type of the object returned by InvokeScript will vary. If the called Active Scripting function returns scalar data, such as a string or an integer, it will be returned as a string ...
It seems that integers will be returned as string, you could asume that the same applies to doubles.
EDIT:
I forgot that you were talking about an array. Anyhow, MSDN continues:
... If it returns a script-based object, such as an object created using JScript or VBScript's new operator, it will be of type Object ...
So it seems that you will get an object instead, but that doesn't help the fact that you will have to convert it inside your C# code.
EDIT 2:
As for the conversion of the actual ComObject. After reading this which is about Excel, but it still returns a ComObject, it seems that your current aproach with the string seems like the simpler one. Sometimes a hack is the best solution :D
This "problem" amounts to transforming VARIANT into an C# array. For this probably the easiest way is to use reflection. Here is how:
private static IEnumerable<object> SafeArrayToEnmrble (object comObject)
{
Type comObjectType = comObject.GetType();
// spot here what is the type required
if (comObjectType != typeof(object[,]))
// return empty array, throw exception or whatever is your fancy
return new object[0];
int count = (int)comObjectType.InvokeMember("Length", BindingFlags.GetProperty, null, comObject, null);
var result = new List<object>(count);
var indexArgs = new object[2];
for (int i = 1; i <= count; i++)
{
indexArgs[0] = i;
indexArgs[1] = 1;
object valueAtIndex = comObjectType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObject, indexArgs);
result.Add(valueAtIndex);
}
return result;
}

Passing Argument To Method that Requires "ref System.Array"

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;
}
}

Categories

Resources