Unable to cast from object array to a string array - c#

This is my function.
public Dictionary<string, string> ArrayToDictionaryConverter(object [] objArray)
{
string[] strArray = new string[objArray.Length];
strArray =(string[])objArray;
Dictionary<string, string> dictionary = null;
try
{
dictionary = new Dictionary<string, string>();
for (int iVal = 0; iVal < strArray.Length; )
{
dictionary.Add(strArray[iVal], strArray[iVal + 1]);
iVal += 2;
}
}
catch (Exception ex)
{
}
return dictionary;
}
Getting error :
Unable to cast object of type 'System.Object[]' to type 'System.String[]'.
Why ? is this wrong convention / Casting?

You can't cast an expression to a particular type if it's not actually of that type, or a compatible one (or there's an explicit conversion).
In this case, the array wasn't a string[] - it was an object[]. It could have been a string[], which is why the compiler allowed you to write the cast in the first place - but at execution time the CLR found that it was just an object[].
Do you expect every element in the array to already be a string? If so, you should just cast each element individually. If not, you'll have to add a call to ToString (or some other way of converting each element to a string) - but be careful of null values.
As an aside, empty catch blocks are a really bad idea. What do you really want to happen if something goes wrong? And what kind of errors do you want to handle in what way? Some errors to think about:
What if one of the keys is null?
What if you get duplicate keys?
What if the input array has an odd number of elements?
Finally, I'd suggest putting the i += 2 in the for loop "header" instead of at the end of the block.

Try the Array.ConvertAll method.

See This is working:
public Dictionary ArrayToDictionaryConverter(object [] objArray)
{
string[] strArray = Array.ConvertAll(objArray,Convert.ToString);
Dictionary dictionary = null;
try
{
dictionary = new Dictionary();
for (int iVal = 0; iVal < strArray.Length; )
{
dictionary.Add(strArray[iVal], strArray[iVal + 1]);
iVal += 2;
}
}
catch (Exception ex)
{
}
return dictionary;
}

Related

How to convert array of string to enum?

How can I convert an array of string to enum?
The following code gives a basic idea about what is expected,
permission.Permissions.Add(Enum.Parse(typeof(PagePermission) ,a );
however, it throws an error like
can not convert object to enum.
Here, PagePermission is enum.
string pagePermission = "View,Edit";
string[] permissions = pagePermission.Split(',');
permission.Permissions = new List<PagePermission>();
for (int i = 0; i < permissions.Length; i++)
{
string a = permissions[i];
permission.Permissions.Add(Enum.Parse(typeof(PagePermission) ,a );
}
Use this
IEnumerable<myEnum> items = myArray.Select(a => (myEnum)Enum.Parse(typeof(myEnum), a));
Enum.Parse returns an object, you need to cast it to the actual enum type. In your case:
permission.Permissions.Add((PagePermission)Enum.Parse(typeof(PagePermission), a);
Otherwise you'd be adding an object to a list of PagePermission, which causes the error you had.

Let the user store value into a string array C#

I'm having some trouble letting a user save his value into an array, here's the code that I tried with:
I want to be able to store up to 4 objects, and then reset them with null, if that is possible.
string [] array = new string[4];
array[i] += Console.ReadLine(); //and now it says: Cannot implicitly convert
type 'string' to 'int'. I also want to reset the value with this code:
array[i] = null;
I'm new to arrays and it's really hard. Thanks in advance!
The problem is in i variable that has a type string instead of int. You need to use integer values for your indexer in array.
Also there is no reason to use += operator. Just assign your value to the array element by using =.
var index = int.Parse(i); // the better way is to use TryParse to check your i string contains integer value
array[index] = Console.ReadLine();
Looks to me like you are trying to index the array using a name. If so, I would use a Dictionary instead:
var key = "MyValueKey"; //I presume this is currently your "i" value
var dict = new Dictionary<String, String>();
var userVal = Console.ReadLine();
if (String.IsNullOrWhitespace(userVal))
userVal = null;
if (dict.ContainsKey(key))
dict[key] = userVal;
else
dict.Add(key, userVal);

Assign a formula at runtime for accessing elements of List

The scenario is that I have say two different types of cases - case 1 and case 2. For case 1 and case 2 each I have a certain startIndex, endIndex and a formula for accessing the elements of a List.
Now for assigning values startIndex and endIndex I am preferring a normal switch case, however I am at loss for the formula for accessing elements. For case 1 it is say something like List[ a+i ] and for case 2 it is say List[a + (i-b)].
One way can be to have a for loop like this
for(int i=0;;i++)
{
if(case is 1)
then f=a+i
else if(case 2)
then f=a+(i-b)
}
I thought of using delegates. however, as per my knowledge they need to be made global. Actions do not return value. Func can be used but one expression/formula takes only one element (int) and the other takes 3. I need something in lines to this like that anonymous function can be assigned any of above mentioned formulae at runtime from the switch case (as the cases might and will increase in future).
Thank you.
I thought of using delegates. however, as per my knowledge they need
to be made global.
This is not true (actually, there are no truly global variables in C#, since each and every variable needs to be encapsulated inside an object). A public delegate type is indeed visible to all code after referencing the assembly containing this type's code, but a variable of such type can be private.
What I recommend in your situation is to have some sort of mapping from case numbers to delegates. A good idea is to use a Dictionary<TKey, TValue> if you have at most one delegate per case. This dictionary can be stored as a private variable inside the class where your method resides.
public class MyClass
{
private Dictionary<int, Delegate> _delegateMapping = new Dictionary<int, Delegate>;
}
There are a couple of ways you can add elements do the dictionary in the constructor: passing the already populated dictionary, passing an array of delegates, creating these delegates in the constructor itself. Either way, you'll end up with a dictionary of Delegate types, so you'll need to use a cast to be able to use them in your code properly.
for (int i = 1; i < _delegateMapping.Count; i++)
{
switch (i)
{
case 1:
var f = (Action<int>)_delegateMapping[1];
f(i);
break;
case 2:
var f = (Action<int, int>)_delegateMapping[2];
f(i, a);
break;
}
}
Of course I'm greatly improvising here.
It is important to note that if the type of delegate changes inside the dictionary, you will have to modify the cast accordingly inside the switch statement. Otherwise, if no implicit cast exists, you'll get a runtime exception.
Hi guys thank you so very much for your feedbacks. I finally found the solution with Func. This is what my code looks like. I had to manipulate the Func usage a little. I made almost all the vars which I have to use in the Func as global/local to the function where I write these Funcs. My apologies, if I was not able to explain my problem properly.
int i = -1;
Func<int,int> formula = null;
switch(f)
{
case 1:
{
formula = new Func<int,int>(index => { return i; });
}
break;
case 2:
{
formula = new Func<int, int>( index => { return s- (i * c); } );//here s and c are global variables.
}
break;
}
i = startIndex;
while(i < endIndex)
{
var Obj= List[formula.Invoke(i)];
//my code goes here
i++;
}
Let me know if my solution is correct w.r.t performance, logic, C# programming, etc.. :)
EDITED::
#usr and #Kapol I tried the way you suggested and tried to improvise the code like this.
private Dictionary<int, Func<int[], int>> indexFormulae;
private void assignDelegates()
{
indexFormulae = new Dictionary<int, Func<int[], int>>();
indexFormulae.Add(0, getFormula_1);
indexFormulae.Add(1, getFormula_2);
}
private void someFunction(int sp)
{
int i = 0;
Func<int[], int> formula = null;
indexFormulae.TryGetValue(formation,out formula);
i = startIndex;
while (i < endIndex)
{
int[] intValues = new int[] {i,sp,globalVar };
var Obj = List[formula.Invoke(intValues)];
//My code here
i++;
}
}
private int getFormula_1(params int[] intValues)
{
return intValues[0];
}
private int getIndex_Vertical(params int[] intValues)
{
return intValues[1] - (intValues[0] * intValues[2]);
}
So, that with this now I can use these two getFormula methods anywhere in this class rather than keeping them anonymous. and also I think I will stick to params because I might have N number of int params in future for other functions.

How to convert object to object[]

I have an object whose value may be one of several array types like int[] or string[], and I want to convert it to a string[]. My first attempt failed:
void Do(object value)
{
if (value.GetType().IsArray)
{
object[] array = (object[])value;
string[] strings = Array.ConvertAll(array, item => item.ToString());
// ...
}
}
with the runtime error Unable to cast object of type 'System.Int32[]' to type 'System.Object[]', which makes sense in retrospect since my int[] doesn't contain boxed integers.
After poking around I arrived at this working version:
void Do(object value)
{
if (value.GetType().IsArray)
{
object[] array = ((Array)value).Cast<object>().ToArray();
string[] strings = Array.ConvertAll(array, item => item.ToString());
// ...
}
}
I guess this is OK, but it seems pretty convoluted. Anyone have a simpler way?
You don't need to convert it to an array and then use LINQ. You can do it in a more streaming fashion, only converting to an array at the end:
var strings = ((IEnumerable) value).Cast<object>()
.Select(x => x == null ? x : x.ToString())
.ToArray();
(Note that this will preserve nulls, rather than throwing an exception. It's also fine for any IEnumerable, not just arrays.)
.ToArray makes multiple memory allocations in most cases, but there are few ways around it:
object value = new[] { 1, 2.3 };
IList list = value as IList;
string[] strings = new string[list.Count];
for (int i = 0; i < strings.Length; i++)
strings[i] = Convert.ToString(list[i]);
In most cases that might be a bit overkill and waste of vertical space, so I would use something like the accepted answer with an optional null-conditional operator ? to check if the source is array:
string[] strings = (value as Array)?.Cast<object>().Select(Convert.ToString).ToArray();
void Do(object value)
{
if (value.GetType().IsArray)
{
string[] strings = ((object[]) value).Select(obj => Convert.ToString(obj)).ToArray();
}
}

Proper nullable type checking in C#?

Ok, my actual problem was this: I was implementing an IList<T>. When I got to CopyTo(Array array, int index), this was my solution:
void ICollection.CopyTo(Array array, int index)
{
// Bounds checking, etc here.
if (!(array.GetValue(0) is T))
throw new ArgumentException("Cannot cast to this type of Array.");
// Handle copying here.
}
This worked in my original code, and still works. But it has a small flaw, which wasn't exposed till I started building tests for it, specifically this one:
public void CopyToObjectArray()
{
ICollection coll = (ICollection)_list;
string[] testArray = new string[6];
coll.CopyTo(testArray, 2);
}
Now, this test should pass. It throws the ArgumentException about not being able to cast. Why? array[0] == null. The is keyword always returns false when checking a variable that is set to null. Now, this is handy for all sorts of reasons, including avoiding null dereferences, etc. What I finally came up with for my type checking was this:
try
{
T test = (T)array.GetValue(0);
}
catch (InvalidCastException ex)
{
throw new ArgumentException("Cannot cast to this type of Array.", ex);
}
This isn't exactly elegant, but it works... Is there a better way though?
There is a method on Type specifically for this, try:
if(!typeof(T).IsAssignableFrom(array.GetElementType()))
The only way to be sure is with reflection, but 90% of the time you can avoid the cost of that by using array is T[]. Most people are going to pass a properly typed array in, so that will do. But, you should always provide the code to do the reflection check as well, just in case. Here's what my general boiler-plate looks like (note: I wrote this here, from memory, so this might not compile, but it should give the basic idea):
class MyCollection : ICollection<T> {
void ICollection<T>.CopyTo(T[] array, int index) {
// Bounds checking, etc here.
CopyToImpl(array, index);
}
void ICollection.CopyTo(Array array, int index) {
// Bounds checking, etc here.
if (array is T[]) { // quick, avoids reflection, but only works if array is typed as exactly T[]
CopyToImpl((T[])localArray, index);
} else {
Type elementType = array.GetType().GetElementType();
if (!elementType.IsAssignableFrom(typeof(T)) && !typeof(T).IsAssignableFrom(elementType)) {
throw new Exception();
}
CopyToImpl((object[])array, index);
}
}
private void CopyToImpl(object[] array, int index) {
// array will always have a valid type by this point, and the bounds will be checked
// Handle the copying here
}
}
EDIT: Ok, forgot to point something out. A couple answers naively used what, in this code, reads as element.IsAssignableFrom(typeof(T)) only. You should also allow typeof(T).IsAssignableFrom(elementType), as the BCL does, in case a developer knows that all of the values in this specific ICollection are actually of a type S derived from T, and passes an array of type S[]
List<T> uses this:
try
{
Array.Copy(this._items, 0, array, index, this.Count);
}
catch (ArrayTypeMismatchException)
{
//throw exception...
}
Here is a little test of try / catch vs. reflection:
object[] obj = new object[] { };
DateTime start = DateTime.Now;
for (int x = 0; x < 1000; x++)
{
try
{
throw new Exception();
}
catch (Exception ex) { }
}
DateTime end = DateTime.Now;
Console.WriteLine("Try/Catch: " + (end - start).TotalSeconds.ToString());
start = DateTime.Now;
for (int x = 0; x < 1000; x++)
{
bool assignable = typeof(int).IsAssignableFrom(obj.GetType().GetElementType());
}
end = DateTime.Now;
Console.WriteLine("IsAssignableFrom: " + (end - start).TotalSeconds.ToString());
The resulting output in Release mode is:
Try/Catch: 1.7501001
IsAssignableFrom: 0
In debug mode:
Try/Catch: 1.8171039
IsAssignableFrom: 0.0010001
Conclusion, just do the reflection check. It's worth it.

Categories