c# multidimensional array conversion - c#

I want to convert a multidimensional array of int[,] to an array of ushort[,] and if possible without looping over each dimension.
I found a post where object[,] is converted to double[,] by using Array.Copy. Unfortunately this only works because the objects are allready of type double. Is there any chance to achieve a similar result for converting int to ushort (assuming it always fits)?
var input = new [,]
{
{1,1,1},
{2,2,2},
{3,3,3}
};
var output = new ushort[3, 3];
// Convert
Array.Copy(input, output, input.Length);
The above code compiles, but fails on execution because it can not convert from int to ushort. I know why this happens, I just want to tell .NET that it should just convert.
As I said I know the easiest solution are two loops. I am just curious if there is an alternative.
Conclusion: Unfortunately there is no fast and built-in way to do this. Therefore I recommend the obvious and readable solution of going for the double loop unless you really need lightning speed fast conversion.
for(var i=0; i<input.GetLength(0); i++)
for(var j=0; j<input.GetLength(1); j++)
output[i,j] = (ushort)input[i,j];
However this is not the accepted solution since for my personal interest I was asking for the fastest alternative and that is, as expected, and evil and unsafe pointer conversion.

This will work without any conversion overhead. Also, it's evil, but I'd do it.
static unsafe void FastCopy(int[,] source, ushort[,] destination)
{
//pin the source and destination arrays
fixed (int* pSource = source) fixed (ushort* pDestination = destination)
{
//compute the pointers for the elements just past the arrays
//as termination conditions
var pSourceEnd = pSource + source.Length;
var pDestinationEnd = pDestination + destination.Length;
//setup our iterator variables
var pSourceCurrent = pSource;
var pDestinationCurrent = pDestination;
//loop over each element until you run out of elements in
//either the source or destination
while (pSourceCurrent < pSourceEnd && pDestinationCurrent < pDestinationEnd)
{
//copy the two lowest bytes in each source int to the
//destination ushort
*pDestinationCurrent++ = *(ushort*)pSourceCurrent++;
}
}
}

Well, you can't convert in-place because arrays are low-level structures, so the memory footprint of an int[,] and a ushort[,] would be different. Also, there's not a built-in method to convert a 2-D array, so the simplest option is to loop and fill a new array with the converted values.

You seem to be conflating very different types of "casts". Do not mix reference conversions with type conversions and boxing conversions:
class Foo: IFoo { ... }
var foo = new Foo();
var iFoo = foo; //implicit reference conversion
var i = 1;
var o = (object)i; //boxing
var u = (uint)i; //type conversion
Reference conversions do not change the object at all, they only change the type of the reference pointing at it. Type conversions (for lack of a better term, english is not my native language) give you back an alltogether different object. Boxing and unboxing conversions are special but behavior wise, in the scope of your question, are similar to reference conversions.
That C# has the same syntax for all these semantically very different casts is, in my opnion, unfortunate.
Array.Copy will allow you to copy between arrays of different type when there is a reference type conversion or boxing/unboxing coversion between them. The reason being that you are not really changing the object, just it's reference (the bits that make up the object stay the same and therefore its size too (again, not strictly true with boxing/unboxing)). That is, the following are all valid:
var foos = new Foo[] { null, null, null };
var iFoos = new IFoo[3];
Array.Copy(foos, iFoos, 3); //reference conversion
var ints = new[] { 1, 2, 3 };
var objs = new object[3];
Array.Copy(ints, objs, 3); //boxing conversion
Array.Copy(objs, ints, 3); //unboxing conversion
While the following is not:
var ints = new[] { 1, 2, 3 };
var uints = new uint[3];
Array.Copy(ints, uints, 3); //type conversion. Runtime error.
Worth noting that the following is also not valid:
var objs = new object[] { 1, 2, 3 }; //boxed int[]
var uints = new uint[3];
Array.Copy(objs, uints, 3); // Unboxing conversion. Runtime error. Huh?
Why is that? Isn't there an unboxing conversion from object to uint? Yes there is, but the boxed value is really an int and you can only unbox a boxed value to its real type. Due to the same reason, the following will also give you a runtime error:
obect i = 1;
var u = (uint)i;
So what does that have to do with anything you've asked?
Well, that there is no inbuilt way to convert a n-dimensional array from one type array to another if the conversion is not a simple reference or boxing/unboxing conversion. You either have to flatten the array using Linq or create your own extension method and in either case you will have to iterate the array to perform the conversion because you have to create a new object (potentially with different size, bits, etc.) for each element in the source array.
Obviosuly, performance will be significantly slower than Array.Copy.

Related

What is the difference between directly casting an array or using System.Linq.Cast?

Suppose I have 2 classes, A and B, and B can be cast to A. I declared an array of type B[] called b. Then if I wanted to cast b to A[], what's the difference between (A[])b and b.Cast<A>()?
These are two different things.
Language casting
(A[])b cast b to type A[] and does not compile or throws an exception at runtime if b is not type of A[].
Take for example the case of doubles and integers:
var array = new object[2];
array[0] = 10.2;
array[1] = 20.8;
var casted = (int[])array; // does not compile here,
// or throw an exception at runtime if types mismatch
Here we just cast a type to another, no matter what they are, collection or not.
Casting and type conversions (C# Programming Guide)
Linq Cast
Cast<TResult> convert each items of an IEnumerable to TResult.
It's just a LINQ loop already written to make our life easier over boxed values.
Enumerable.Cast(IEnumerable) Method
Casts the elements of an IEnumerable to the specified type.
From the source code
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
foreach (object obj in source) yield return (TResult)obj;
}
Thus this method can be used to unbox boxed values from a collection like Rows of a DataGridView or any similar "reduced" collections like for example Items in a ListBox or a ComboBox.
That means that the type of the items must be type of TResult or ancestor.
Example
var array = new object[2];
array[0] = 10.2;
array[1] = 20.8;
var converted = array.Cast<int>(); // compiles but will not work
// and throw an InvalidCastException
Note
Because of the yielding, Cast method is deferred, so we get the result only when it is executed, for example using foreach or ToList.
Deferred Execution of LINQ Query
Deferred Vs Immediate Query Execution in LINQ
Deferred execution and lazy evaluation
Alternative to solve the problem on the sample
Therefore to convert the array, we can use a direct cast using for example a foreach or Select:
var converted = array.Select(v => (int)v).ToArray(); // get int[]
Console.WriteLine(string.Join(Environment.NewLine, converted));
> 10
> 20
Using an extension method
static public class EnumerableHelper
{
static public IEnumerable<TResult> Cast<TSource, TResult>(this IEnumerable<TSource> source)
where TSource : IConvertible
{
foreach ( TSource obj in source )
yield return (TResult)Convert.ChangeType(obj, typeof(TResult));
}
}
var converted = array.Cast<double, int>();
> 10
> 21
Also CultureInfo.InvariantCulture to avoid problems on numbers, as well as a formatter to avoid roundings.
.Cast<T> is from Linq. It will enumerate the collection casting each item to T and creating a new sequent. The other is an explicit cast, telling the compiler you would want to access the original as that type.
Your two examples, while different, are both invalid.
You cannot cast an array of one object type to another, even if there exists a conversion operator between them (explicit or implicit). The compiler rightly prevents such a cast. The exception to this rule is if there exists an inheritance relationship; thanks to array covariance you can downcast to a base type (for reference types). The following works:
class A {}
class B : A {}
B[] bs = new[] { new B() };
A[] result = (A[])bs; // valid
See SharpLab
The same principles hold true for the Cast<T> method in LINQ--unless the types match, an exception will be thrown at runtime upon enumeration. The answer below is incorrect. You cannot, for example, Cast an array of double to int. Of course, if you don't enumerate the result (such as in the example) then no exception occurs. However upon actually enumerating (foreach, ToList, ToArray) an InvalidCastException will be thrown.
var array = new double[2];
array[0] = 10;
array[1] = 20;
var temp = array.Cast<int>(); // OK, not enumerated
var converted = temp.ToList(); // bam! InvalidCastException
Notice the temp variable--as in the answer below it doesn't throw thanks to LINQ's deferred execution. It's once you enumerate it that it fails. See SharpLab.
The Cast method was designed to bridge the gap with pre-generic collections where values were stored internally as an array of object and the collections themselves only implement IEnumerable. Cast allows one to convert to IEnumerable<T>, however no casting/converting other than from object to the original type is allowed.
For structs this is obvious--a boxed double can only be unboxed to a double; it cannot be unboxed to an int. Take the simple, non-array case:
double d = 1.5;
object o = d;
int iOk = (int)(double)o; // ok
int iBad = (int)o; // fails
See SharpLab
It makes sense then, that Cast<int> will fail as the method only inserts the single cast to int, and not the intermediate cast to double that would otherwise be required.
For classes, again Cast will only insert the direct cast. The method is generic and does not/cannot account for any user defined operators. So when you say you "have two classes that can be cast to each other" this still would not matter. In other words, the following will fail:
class A {}
class B {
public static implicit operator A(B b) => new A();
}
B[] bs = new[] { new B() };
var temp = bs.Cast<A>(); // OK, not yet enumerated
A[] result = temp.ToArray(); // throws InvalidCastException
See SharpLab
Again (as above), the exception to this rule is if there exists an inheritance relationship between the two classes. You can downcast from one to the other:
class A {}
class B : A {}
B[] bs = new[] { new B() };
A[] result = bs.Cast<A>().ToArray(); // valid
See SharpLab
One alternative is to use LINQ's Select to project your original collection, applying the conversion operators you desire:
class A {}
class B {
public static implicit operator A(B b) => new A();
}
B[] bs = new[] { new B() };
A[] result = bs.Select(b => (A)b).ToArray(); // valid!
See SharpLab. This would also work in the case of the double/int:
var array = new double[] { 10.2, 20.4 };
int[] result = array.Select(d => (int)d).ToArray();
See SharpLab

In C#, is it possible to cast a byte array into another type without creating a new array?

I have a byte[] object that I'm using as a data buffer.
I want to "read" it as an array of a either primitive/non-primitive structs without duplicating the byte[] data in memory.
The goal would be something like:
byte[] myBuffer;
//Buffer is populated
int[] asInts = PixieDust_ToInt(myBuffer);
MyStruct[] asMyStructs = PixieDust_ToMyStruct(myBuffer);
Is this possible? If so, how?
Is it possible? Practically, yes!
Since .NET Core 2.1, MemoryMarshal lets us do this for spans. If you are satisfied with a span instead of an array, then yes.
var intSpan = MemoryMarshal.Cast<byte, int>(myByteArray.AsSpan());
The int span will contain byteCount / 4 integers.
As for custom structs... The documentation claims to require a "primitive type" on both sides of the conversion. However, you might try using a ref struct and see that is the actual constraint. I wouldn't be surprised if it worked!
Note that ref structs are still very limiting, but the limitation makes sense for the kind of reinterpret casts that we are talking about.
Edit: Wow, the constraint is much less strict. It requires any struct, rather than a primitive. It does not even have to be a ref struct. There is only a runtime check that will throw if your struct contains a reference type anywhere in its hierarchy. That makes sense. So this should work for your custom structs as well as it does for ints. Enjoy!
You will not be able to do this. To have a MyStruct[] you'll need to actually create such an array of that type and copy the data over. You could, in theory, create your own custom type that acted as a collection, but was actually just a facade over the byte[], copying the bytes out into the struct objects as a given value was accessed, but if you end up actually accessing all of the values, this would end up copying all of the same data eventually, it would just potentially allow you to defer it a bit and may be helpful if you only actually use a small number of the values.
Consider class System.BitConverter
This class has functions to reinterpret the bytes starting at a given index as an Int32, Int64, Double, Boolean, etc. and back from those types into a sequence of bytes.
Example:
int32 x = 0x12345678;
var xBytes = BitConverter.GetBytes(x);
// bytes is a byte array with length 4: 0x78; 0x56; 0x34; 0x12
var backToInt32 = BitConverter.ToInt32(xBytes, 0);
Or if your array contains mixed data:
double d = 3.1415;
int16 n = 42;
Bool b = true;
Uint64 u = 0xFEDCBA9876543210;
// to array of bytes:
var dBytes = BitConverter.GetBytes(d);
var nBytes = BitConverter.GetBytes(n);
var bBytes = BitConverter.GetBytes(b);
var uBytes = BitConterter.GetBytes(u);
Byte[] myBytes = dBytes.Concat(nBytes).Concat(bBytes).Concat(uBytes).ToArray();
// startIndexes in myBytes:
int startIndexD = 0;
int startIndexN = dBytes.Count();
int startIndexB = startIndexN + nBytes.Count();
int startIndexU = startIndexB + bBytes.Count();
// back to original elements
double dRestored = Bitconverter.ToDouble(myBytes, startIndexD);
int16 nRestored = BitConverter.ToInt16(myBytes, startIndexN);
bool bRestored = BitConverter.ToBool(myBytes, startIndexB);
Uint64 uRestored = BitConverter.ToUint64(myBytes, startIndexU);
The closest you will get in order to convert a byte[] to other base-types is
Byte[] b = GetByteArray();
using(BinaryReader r = new BinaryReader(new MemoryStream(b)))
{
r.ReadInt32();
r.ReadDouble();
r.Read...();
}
There is however no simple way to convert a byte[] to any kind of object[]

Convert an array of pointers to an array of IntPtr

I'm stuck on a seemingly trivial task and need your help.
I need to write a method with the following signature:
System.Array ToIntPtrArray(System.Array a)
where an actual argument can be an array of any pointer type (e.g. int*[], long**[], void*[,]) and returning an array of the same shape with elements of type System.IntPtr having the same numeric values as elements of an input array. The problem is that I do not understand how to extract numeric values of pointers if I do not know their types beforehand.
For example, if I knew beforehand that my argument is always of type void*[], I could write the method as follows:
unsafe IntPtr[] ToIntPtrArray(void*[] a)
{
var result = new IntPtr[a.Length];
for (int i = 0; i < a.Length; i++)
result[i] = (IntPtr) a[i];
return result;
}
But the problem is it could be not void*[], but void**[] or anything else, and the method should be able to handle all cases.
The short answer is, this cannot be done directly. The reasons are that if you pass your conversion function any of the conventional index-capable containers (System.Array, Collections.IList, ArrayList, etc.) performing the index operations will attempt to cast the result to System.Object. Pointers in C# do not derive from Object, so this will result in an SystemNotSupported or similar exception.
There are two reasonable workarounds:
Convert the pointer arrays to void pointer arrays before calling the
method.
Convert the pointer arrays to void pointer pointers before
calling the method.
The first one is rather cumbersome, as it requires duplicating the entire contents of the array with a for loop. The second option requires passing in the length of the array as it is no longer wrapped with a managed System.Array object.
Sample Code
Method:
unsafe Array ToIntPtrArray(void** a, int count)
{
IntPtr[] intPtrArray = new IntPtr[count];
for (int n = 0; n < count; n++)
intPtrArray[n] = new IntPtr(a[n]);
return intPtrArray;
}
Sample Usage (integer pointer array):
int*[] intPtrArray;
// Code that initializes the values of intPtrArray
fixed(int** ptr = &intPtrArray[0])
{
Array result = ToIntPtrArray((void**)ptr, intPtrArray.Length);
}
Sample Usage (void pointer pointer array):
void**[] voidPtrPtrArray;
// Code that initializes the values of voidPtrPtrArray
fixed(void*** ptr = &voidPtrPtrArray[0])
{
Array result = ToIntPtrArray((void**)ptr, voidPtrPtrArray.Length);
}
Sample Usage (multidimensional int pointer array):
int*[,] int2dArray;
// Code that initializes the values of int2dArray
fixed(int** ptr = &int2dArray[0,0])
{
Array result = ToIntPtrArray((void**)ptr, TotalSize(int2dArray));
Array reshaped = ReshapeArray(result,int2dArray);
}
Where TotalSize and ReshapeArray are helper functions that are written to deal with multi-dimensional arrays. For tips on how to accomplish this see: Programatically Declare Array of Arbitrary Rank.
This is a rather difficult problem. Creating an array of the proper shape isn't too bad.
unsafe System.Array ToIntPtrArray(System.Array a)
{
int[] lengths = new int[a.Rank];
int[] lowerBounds = new int[a.Rank];
for (int i = 0; i < a.Rank; ++i)
{
lengths[i] = a.GetLength(i);
lowerBounds[i] = a.GetLowerBound(i);
}
Array newArray = Array.CreateInstance(typeof (IntPtr), lengths, lowerBounds);
// The hard part is iterating over the array.
// Multiplying the lengths will give you the total number of items.
// Then we go from 0 to n-1, and create the indexes
// This loop could be combined with the loop above.
int numItems = 1;
for (int i = 0; i < a.Rank; ++i)
{
numItems *= lengths[i];
}
int[] indexes = new int[a.Rank];
for (int i = 0; i < numItems; ++i)
{
int work = i;
int inc = 1;
for (int r = a.Rank-1; r >= 0; --r)
{
int ix = work%lengths[r];
indexes[r] = lowerBounds[r] + ix;
work -= (ix*inc);
inc *= lengths[r];
}
object obj = a.GetValue(indexes);
// somehow create an IntPtr from a boxed pointer
var myPtr = new IntPtr((long) obj);
newArray.SetValue(myPtr, indexes);
}
return newArray;
}
That creates an array of the right type and shape (dimensions and length), but it has a problem. The GetValue method, which you use to get an item from the array, returns an object. And you can't cast a pointer type to an object. No way, no how. So you can't get the value from the array! If you call GetValue on an array of long*, for example, you'll get "type not supported."
I think you need some way to copy that oddly-shaped array to a one-dimensional array of int* (or any other pointer type). Then you could directly index the temporary array and get the values to populate your IntPtr array.
It's an interesting chicken-and-egg problem. If you pass it as a System.Array, then you can't get items from it because there's no conversion path from object to int* (or any other pointer type). But if you pass it as a pointer type (i.e. int**), then you can't get the shape of the thing.
I suppose you could write it as:
unsafe System.Array ToIntPtrArray(System.Array a, void** aAsPtr)
You then have the System.Array metadata and the actual data in a form that you can use.
Even though the question has been answered well, I feel the need to leave a note/warning to future readers.
The CLR is designed to keep you safe, or at least as safe as possible. It accomplishes this with (among other things) type safety and abstracting memory operations. While you can turn some of these protections off with the unsafe block, some protections are hardcoded into the compiler/runtime. In order to circumvent this additional hurdle, one must resort to some hackey, and possibly slow, code. While these methods work, experience has taught me that doing such things leads to problems down the road, whether it be a change in the runtime, a future programmer needing to modify that segment of code, or you yourself needing to do something else with those pointers later on in the code.
At this point, I would seriously consider a helper dll written in Managed C++ to handle the "raw pointer" side of things. My reasoning is that by using Unsafe, you're already throwing out many protections the CLR offers. You may find it easier to work unencumbered by any additional, baked in protections. Not to mention you can use pointers to their full extent, and then cast them back to intptr when you're done. If nothing else, you may want to look at implementing ToIntPtrArray in C++. Still pass it pointers on the C# side, but escape the CLR's oversight.
Note that I'm not saying that every time you use "unsafe" you should bust out the C++. Quite contrary - unsafe will allow you to do quite a bit - but in this instance, a C++ helper is probably something to consider.
Disclaimer: I have not done a whole lot with managed C++. It could be that I am totally wrong and the CLR would still monitor the pointers. If some more experienced soul could comment and tell me either way, It'd be much appreciated.

Difference between Casting, Parsing and Converting [duplicate]

This question already has answers here:
Is casting the same thing as converting?
(11 answers)
Closed 9 years ago.
I have been working on some code for a while. And I had a question: What's the difference among casting, parsing and converting? And when we can use them?
Casting is when you take a variable of one type and change it to a different type. You can only do that in some cases, like so:
string str = "Hello";
object o = str;
string str2 = (string)o; // <-- This is casting
Casting does not change the variable's value - the value remains of the same type (the string "Hello").
Converting is when you take a value from one type and convert it to a different type:
double d = 5.5;
int i = (int)d; // <---- d was converted to an integer
Note that in this case, the conversion was done in the form of casting.
Parsing is taking a string and converting it to a different type by understanding its content. For instance, converting the string "123" to the number 123, or the string "Saturday, September 22nd" to a DateTime.
Casting: Telling the compiler that an object is really something else without changing it (though some data loss may be incurred).
object obj_s= "12345";
string str_i = (string) obj; // "12345" as string, explicit
int small = 12345;
long big = 0;
big = small; // 12345 as long, implicit
Parsing: Telling the program to interpret (on runtime) a string.
string int_s = "12345";
int i = int.Parse(int_s); // 12345 as int
Converting: Telling the program to use built in methods to try to change type for what may be not simply interchangeable.
double dub = 123.45;
int i = System.Convert.ToInt32(dub); // 123 as int
These are three terms each with specific uses:
casting - changing one type to another. In order to do this, the
types must be compatible: int -> object; IList<T> -> IEnumerable<T>
parsing - typically refers to reading strings and extracting useful parts
converting - similar to casting, but typically a conversion would involve changing one type to an otherwise non-compatible type. An example of that would be converting objects to strings.
A cast from one type to another requires some form of compatibility, usually via inheritance or implementation of an interface. Casting can be implicit or explicit:
class Foo : IFoo {
// implementations
}
// implicit cast
public IFoo GetFoo() {
return Foo;
}
// explicit cast
public IFoo GetFoo() {
return Foo as IFoo;
}
There are quite a few ways to parse. We read about XML parsing; some types have Parse and TryParse methods; and then there are times we need to parse strings or other types to extract the 'stuff we care about'.
int.Parse("3") // returns an integer value of 3
int.TryParse("foo", out intVal) // return true if the string could be parsed; otherwise false
Converting may entail changing one type into another incompatible one. This could involve some parsing as well. Conversion examples would usually be, IMO, very much tied to specific contexts.
casting
(casting to work the types need to be compatible)
Converting between data types can be done explicitly using a cast
static void _Casting()
{
int i = 10;
float f = 0;
f = i; // An implicit conversion, no data will be lost.
f = 0.5F;
i = (int)f; // An explicit conversion. Information will be lost.
}
parsing (Parsing is conversion between different types:)
converts one type to another type can be called as parsing uisng int.parse
int num = int.Parse("500");
traversing through data items like XML can be also called as parsing
When user-defined conversions get involved, this usually entails returning a different object/value. user-defined conversions usually exist between value types rather than reference types, so this is rarely an issue.
converting
Using the Convert-class actually just helps you parse it
for more please refer http://msdn.microsoft.com/en-us/library/ms228360%28VS.80%29.aspx
This question is actually pretty complicated...
Normally, a cast just tells the runtime to change one type to another. These have to be types that are compatible. For example an int can always be represented as a long so it is OK to cast it to a long. Some casts have side-effects. For example, a float will drop its precision if it is cast to an int. So (int)1.5f will result in int value 1. Casts are usually the fastest way to change the type, because it is a single IL operator. For example, the code:
public void CastExample()
{
int i = 7;
long l = (long)i;
}
Performs the cast by running the IL code:
conv.i8 //convert to 8-byte integer (a.k.a. Int64, a.k.a. long).
A parse is some function that takes in once type and returns another. It is an actual code function, not just an IL operator. This usually takes longer to run, because it runs multiple lines of code.
For example, this code:
public void ParseExample()
{
string s = "7";
long l = long.Parse(s);
}
Runs the IL code:
call int64 [mscorlib]System.Int64::Parse(string)
In other words it calls an actual method. Internally, the Int64 type provides that method:
public static long Parse(String s) {
return Number.ParseInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
And Number.Parse:
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe static Int64 ParseInt64(String value, NumberStyles options, NumberFormatInfo numfmt) {
Byte * numberBufferBytes = stackalloc Byte[NumberBuffer.NumberBufferBytes];
NumberBuffer number = new NumberBuffer(numberBufferBytes);
Int64 i = 0;
StringToNumber(value, options, ref number, numfmt, false);
if ((options & NumberStyles.AllowHexSpecifier) != 0) {
if (!HexNumberToInt64(ref number, ref i)) {
throw new OverflowException(Environment.GetResourceString("Overflow_Int64"));
}
}
else {
if (!NumberToInt64(ref number, ref i)) {
throw new OverflowException(Environment.GetResourceString("Overflow_Int64"));
}
}
return i;
}
And so on... so you can see it is actually doing a lot of code.
Now where things get more complicated is that although a cast is usually the fastest, classes can override the implicit and explicit cast operators. For example, if I write the class:
public class CastableClass
{
public int IntValue { get; set; }
public static explicit operator int(CastableClass castable)
{
return castable.IntValue;
}
}
I have overridden the explicit cast operator for int, so I can now do:
public void OverridedCastExample()
{
CastableClass cc = new CastableClass {IntValue = 7};
int i = (int)cc;
}
Which looks like a normal cast, but in actuality it calls my method that I defined on my class. The IL code is:
call int32 UnitTestProject1.CastableClass::op_Explicit(class UnitTestProject1.CastableClass)
So anyway, you typically want to cast whenever you can. Then parse if you can't.
Casting: or Parsing
A cast explicitly invokes the conversion operator from one type to another.
Casting variables is not simple. A complicated set of rules resolves casts. In some cases data is lost and the cast cannot be reversed. In others an exception is provoked in the execution engine.
int.Parse is a simplest method but it throws exceptions on invalid input.
TryParse
int.TryParse is one of the most useful methods for parsing integers in the C# language. This method works the same way as int.Parse.
int.TryParse has try and catch structure inside. So, it does not throw exceptions
Convert:
Converts a base data type to another base data type.
Convert.ToInt32, along with its siblings Convert.ToInt16 and Convert.ToInt64, is actually a static wrapper method for the int.Parse method.
Using TryParse instead of Convert or Cast is recommended by many programmers.
source:www.dotnetperls.com
Different people use it to mean different things. It need not be true outside .net world, but here is what I have understood in .net context reading Eric Lippert's blogs:
All transformations of types from one form to another can be called conversion. One way of categorizing may be
implicit -
a. representation changing (also called coercion)
int i = 0;
double d = i;
object o = i; // (specifically called boxing conversion)
IConvertible o = i; // (specifically called boxing conversion)
Requires implicit conversion operator, conversion always succeeds (implicit conversion operator should never throw), changes the referential identity of the object being converted.
b. representation preserving (also called implicit reference conversion)
string s = "";
object o = s;
IList<string> l = new List<string>();
Only valid for reference types, never changes the referential identity of the object being converted, conversion always succeeds, guaranteed at compile time, no runtime checks.
explicit (also called casting) -
a. representation changing
int i = 0;
enum e = (enum)i;
object o = i;
i = (int)o; // (specifically called unboxing conversion)
Requires explicit conversion operator, changes the referential identity of the object being converted, conversion may or may not succeed, does runtime check for compatibility.
b. representation preserving (also called explicit reference conversion)
object o = "";
string s = (string)o;
Only valid for reference types, never changes the referential identity of the object being converted, conversion may or may not succeed, does runtime check for compatibility.
While conversions are language level constructs, Parse is a vastly different thing in the sense it's framework level, or in other words they are custom methods written to get an output from an input, like int.Parse which takes in a string and returns an int.

Why can't I convert an object (which is really object[]) to string[]?

I have a field that is of type 'object'. When I inspect it within the Watch window of visual studio I see its Object[] and when I drill into the elements I see each element is a string.
But when I try to cast this to a String[] I get this error:
Cannot cast 'MyObject' (which has an actual type of 'object[]') to 'string[]' string[]
Any reason why I can't do this cast? What is the best way to convert this object to a string array?
This is a particularly confusing feature of C#. Here's the deal.
Throughout this discussion we assume that the element type of an array is a reference type, not a value type.
C# supports unsafe array covariance. That means that if you have an array of string, you can convert it to an array of object, because a string can be converted to an object:
string[] a1 = { "hello", "goodbye" };
object[] a2 = a1; // Legal
If you then try to get an element out of a2, it works:
object o3 = a2[0];
That's legal because a2[0] is really a1[0], which is a string, which is convertible to object.
However, if you attempt to write to the array then you'll get an error at runtime:
a2[0] = new object();
This fails at runtime because a2 is really an array of strings, and you can't put a non-string into an array of strings.
So C# is already horribly broken; it is possible to write a program that compiles and looks normal but suddenly crashes with a type exception at runtime because you tried to put an object into an array of objects that is not actually an array of objects.
The feature you want is even more broken than that, and thank goodness C# does not support it. The feature you want is:
object[] a4 = { "Hello" };
string[] a5 = a4;
That would be unsafe array contravariance. It breaks horribly like this:
a4[0] = new Customer(); // Perfectly legal
string s6 = a5[0];
And now we just copied a Customer into a variable of type string.
You should avoid any kind of array covariance or contravariance; array contravariance is, as you've discovered, not legal, and array covariance is making little time bombs in your program that go off unexpectedly. Make your arrays of the right type to begin with.
string[] newarr = Array.ConvertAll(objects, s => (string)s);
--EDIT--
since you've said I have an object (knowing that it is an object[] actually)
string[] newarr = Array.ConvertAll((object[])objects, s => (string)s);
object[] original = new object[]{"1", "2"};
//some code in between here
object obj = original ;
object[] objArray = (object[])obj;
string[] newArray = new string[objArray.Length];
for(int i = 0; i < newArray; i++)
{
newArray[i] = (string)objArray[i];
}
Other answers here are showing you quicker/shorter ways of doing the conversion. I wrote the whole thing out like this because it shows what's really going on and what needs to happen. You should use one of the simpler methods in your actual production code.
The rule in object oriented programming is -
"Derived class can always be type casted to base class" AND
"A Base class can be casted to derived class only if the current instance that base class hold off is actually derived class"
e.g. (A is base and B is derived)
A a = new B(); // legal;
B b = (B) a ; // legal as "a" is actually B (in first statement)
illegal : >
A a = new A();
B b = (B) a; // not legal as "a" is A only.
Same thing is applied to Object and String classes. Object is base class and string is Derived class.
You can convert the real string[] to object[].
This is a Array covariance
Can find a clear example in link.
You should cast each element in the collection and not the collection itself.
object[] ovalues = new object[] { "alpha", "beta" };
string[] svalues = ovalues.Cast<string>().ToArray();

Categories

Resources