I have an interesting question regarding C# code.
Basically I have to call a method
BCI2000AutomationLib.IBCI2000Remote.StartupModules(ref System.Array)
Using Visual Studio 2010 the following code compiles and works perfectly:
// Startup modules
string[] modules = new string[3];
modules[0] = "SignalGenerator --local";
modules[1] = "DummySignalProcessing --local";
modules[2] = "DummyApplication --local";
ok_conn = bci.StartupModules(ref modules);
Now porting this to a game engine (e.g. Unity 3D) requires some stricter C# code since it uses Mono C# compiler. So for the same code i get the following compilation error:
The best overloaded method match for
'BCI2000AutomationLib.IBCI2000Remote.StartupModules(ref System.Array)' has some invalid arguments Argument 1: cannot convert
from 'ref string[]' to 'ref System.Array'
Can you please give an advice on how to rewrite this code block to a more strict coding to resolve the stated error?
Change the type of you variable to System.Array
// Startup modules
Array modules = new string[3]
{
"SignalGenerator --local",
"DummySignalProcessing --local",
"DummyApplication --local"
};
ok_conn = bci.StartupModules(ref modules);
Your method StartupModules takes a ref Array as argument ; it can set the variable to any other Array. Not necessarily a string Array, it could be an int[]. That's why you cannot call with a variable typed as Array of string.
String Array program, taking string from user:
class Program
{
static void Main(string[] args)
{
int i,j;
string[] str = new string[10];
Console.WriteLine("Enter the Name of your friends");
for (i = 0; i < 10; i++)
{
str[i] = Convert.ToString(Console.ReadLine());
Console.WriteLine("Array["+i+"]="+str[i]);
}
Console.ReadLine();
}
}
Related
I'm coming from a C++ background. This question has been asked before, but try as I might I cannot find the answer. Let's say I have:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
Can I create a string that references the above (neither of these will compile):
string a = ref ArrayOfReallyVeryLongStringNames[439]; // no compile
string a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
I do understand that strings are immutable in C#. I also understand that you cannot get the address of a managed object.
I'd like to do this:
a = "Donkey Kong"; // Now ArrayOfReallyVeryLongStringNames[439] = "Donkey Kong";
I have read the Stack Overflow question Make a reference to another string in C#
which has an excellent answer, but to a slightly different question. I do NOT want to pass this parameter to a function by reference. I know how to use the "ref" keyword for passing a parameter by reference.
If the answer is "You cannot do this in C#", is there a convenient workaround?
EDIT:
Some of the answers indicate the question was unclear. Lets ask it in a different way. Say I needed to manipulate all items in the original long-named array that have prime indices. I'd like to add aliases to Array...[2], Array...[3], Array...[5], etc to a list. Then, modify the items in the list using a "for" loop (perhaps by passing the list just created to a function).
In C# the "using" keyword creates an alias to a class or namespace. It seems from the answers, that it is not possible to create an alias to a variable, however.
You could create a wrapper that keeps a reference to the underlying array AND the index of the string:
public sealed class ArrayStringReference
{
private readonly string[] _array;
private readonly int _index;
public ArrayStringReference(string[] array, int index)
{
_array = array;
_index = index;
}
public string Value
{
get
{
return _array[_index];
}
set
{
_array[_index] = value;
}
}
public override string ToString()
{
return Value;
}
}
Then this will work:
string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";
var strRef = new ArrayStringReference(ArrayOfReallyVeryLongStringNames, 439);
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Hello world!"
strRef.Value = "Donkey Kong";
Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Donkey Kong"
You could make this more convenient to use by providing an implicit string operator so you don't have to use .Value to access the underlying string:
// Add this to class ArrayStringReference implementation
public static implicit operator string(ArrayStringReference strRef)
{
return strRef.Value;
}
Then instead of having to access the underlying string like this:
strRef.Value = "Donkey Kong";
...
string someString = strRef.Value;
You can do this:
strRef.Value = "Donkey Kong";
...
string someString = strRef; // Don't need .Value
This is just syntactic sugar, but it might make it easier to start using an ArrayStringReference in existing code. (Note that you will still need to use .Value to set the underlying string.)
The closest you can get is this:
unsafe
{
string* a = &ArrayOfReallyVeryLongStringNames[439]; // no compile
}
Which gives an exception:
Cannot take the address of, get the size of, or declare a pointer to a managed type ('string')
So no, not possible...
Also read this MSDN article which explains what types can be used (blittable types).
When I do something like this in C#:
string a = "String 1";
string b = a;
a = "String 2";
Console.WriteLine(a); // String 2
Console.WriteLine(b); // String 1
The thing is, both "String 1" and "String 2" literals are created at the start of the program, and strings are always pointers: at first a references "String 1" literal and afterwards it references "String 2". If you want them to always reference the same thing, in C# you just use the same variable.
The string objects themselves are immutable in C#:
Because a string "modification" is actually a new string creation, you must use caution when you create references to strings. If you create a reference to a string, and then "modify" the original string, the reference will continue to point to the original object instead of the new object that was created when the string was modified.
When the string mutability is needed, for example, to concatenate a lot of strings faster, other classes are used, like StringBuilder.
To sum it up, what you're trying to do is impossible.
In C#, a String is an Object. Therefore String a = "Donkey Kong" says that a now have a reference to this string that is being allocated over the memory. Then all you need to do is:
ArrayOfReallyVeryLongStringNames[439] = a;
And that will copy the refrence (which you should be thinking of in C#!!!) to the location in the string.
BUT!! When you do a="new string";, a will get a new reference. See the example I made:
http://prntscr.com/3kw18v
You can only do this with unsafe mode.
You could create a wrapper
public class StringWrapper
{
public string Value {get;set;}
}
StringWrapper[] arrayOfWrappers = new StringWrapper[500];
arrayOfWrappers[439] = new StringWrapper { Value = "Hello World" };
StringWrapper a = arrayOfWrappers[439];
a.Value = "New Value";
What you are trying to do is universally discouraged, and actively prevented, in C#, where the logic should be independent of the memory model, however, refer to related SO question C# memory address and variable for some info.
EDIT 1
A more canonical approach to your actual problem in C# would be:
// using System.Linq;
string[] raw = new string[] { "alpha", "beta", "gamma", "delta" };
List<int> evenIndices = Enumerable.Range(0, raw.Length)
.Where(x => x % 2 == 0)
.ToList();
foreach (int x in evenIndices)
raw[x] = raw[x] + " (even)";
foreach (string x in raw)
Console.WriteLine(x);
/*
OUTPUT:
alpha (even)
beta
gamma (even)
delta
*/
If you really want to modify the original memory structure itself, then perhaps C++ is a more appropriate language choice for the solution.
EDIT 2
Looking around on SO, you may want to look at this answer Hidden Features of C#? to an unrelated question.
[TestMethod]
public void TestMethod1()
{
string[] arrayOfString = new string[500];
arrayOfString[499] = "Four Ninty Nine";
Console.WriteLine("Before Modification : {0} " , arrayOfString[499]);
string a = arrayOfString[499];
ModifyString(out arrayOfString[499]);
Console.WriteLine("after a : {0}", a);
Console.WriteLine("after arrayOfString [499]: {0}", arrayOfString[499]);
}
private void ModifyString(out string arrayItem)
{
arrayItem = "Five Hundred less one";
}
Of course you can, hehe:
var a = __makeref(array[666]);
__refvalue(a, string) = "hello";
But you would have to have a very good reason to do it this way.
I'm trying to figure out how to use an F# library from a C# assembly, I have used C# quite a bit, but have never used F#.
Here is the F# Class..
namespace FLib
type Class1() =
member this.square(x)=x*x
member this.doit(x, op) = List.map op (Seq.toList(x))|>List.toSeq
member this.squareAllDirect(x) = List.map this.square (Seq.toList(x))|>List.toSeq
member this.squareAllIndirect(x) = this.doit x, this.square
Here is the C# using it
class Program
{
static void Main(string[] args)
{
FLib.Class1 f = new FLib.Class1();
List<int> l=new List<int>(){1,2,3,4,5};
var q =f.squareAllDirect(l);
var r = f.squareIndirect(l);
foreach (int i in r)
Console.Write("{0},",i);
Console.ReadKey();
}
}
The squareAllDirect function works as expected... but the squareAllIndirect call from c# has an exception:
The Type argument for method 'FLib.Class1.squareAllIndirect (System.Tuple,Microsoft.FSharp.Core.FSharpFunc'2>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
It looks you are expecting your squareAllIndirect function to take and returns a int seq
However if you mouse over it you will see it takes and returns a int seq * (int -> int)
Tuple is lower precedence than function call so x is passed as both arguments to doit.
You need to surround the parameters of your function call in ().
member this.squareAllIndirect(x) = this.doit(x, this.square)
That will ensure you take and return what you expect.
This could be very easy, but how can I place or convert a string into an array?
The code that I have, is the following:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string one;
string[] two;
one = "Juan";
two = {one}; // here is the error
HttpContext.Current.Response.Write(two);
}
}
And the error is the following:
Compiler Error Message: CS0029: Cannot implicitly convert type 'string' to 'string[]'
Thanks for you help!
Replace this:
two = {one}; // here is the error
With
two = new[] { one };
OR
two = new string[] { one };
The reason you are getting the error is clear from the error message.
See: Object and Collection Initializers (C# Programming Guide)
Later when you are doing Response.Write, you will get System.String[] as output, since two is an array. I guess you need all array elements separated by some delimiter. You can try:
HttpContext.Current.Response.Write(string.Join(",", two));
Which will produce all the elements in the array separated by comma
It looks like you're trying to use initialization syntax for an assignment. This should work:
two = new string[] {one};
or just
two = new [] {one};
since the compiler will infer that you want a string[]
I think you'll also be surprised what Response.Write(two); produces...
You're using the static initializer syntax to try and add an item to your array. That doesn't work. You can use similar syntax to allocate a new array with the value one - two = new string[] { one }; - or you can allocate the array then add elements through assignment like;
string[] two = new string[10];
two[0] = one; // assign value one to index 0
If you do it like this you have to do some bounds checking for example the following will throw an IndexOutOfRangeException at runtime;
string[] two = new string[10];
int x = 12;
two[x] = one; // index out of range, must ensure x < two.Length before trying to assign to two[x]
That syntax ({one}) is only valid if you declare the array variable in the same line. So, this works:
string one;
one = "Juan";
string[] two = {one};
A more common way to initialize an array, which works in more places, is to use the new keyword, and optionally have the type be inferred, e.g.
string one;
string[] two;
one = "Juan";
// type is inferrable, since the compiler knows one is a string
two = new[] {one};
// or, explicitly specify the type
two = new string[] {one};
I usually declare and initialize on the same line, and use var to infer the type, so I'd probably write:
var one = "Juan";
var two = new[] { one };
What is the meaning of UserName = String(33, 0) in VB 6.0 and what will be the equivalent in C#.
Please help I'm getting error while converting VB 6.0 code into C#.
Thanks in advance.
String in VB6 is a function that returns a string containing a repeating character string of the length specified.
String(number,character)
example:
strTest = String(5, "a")
' strTest = "aaaaa"
strTest = String(5, 97)
' strTest = "aaaaa" (97 is the ASCII code for "a")
In this case, String(33,0) will return a string containing 33 null characters.
The equivalent in C# would be
UserName = new String('\0', 33);
In VB6, that function creates a string that contains 33 characters, all of whom have zero ordinal value.
Typically you do that because you are about to pass the string to some native function which fills out the buffer. In C# the closest equivalent to that would be to create a StringBuilder instance which you would then pass to the native code in a p/invoke function call.
I think that a direct translation of that single line of code is not particularly useful. That code exists in context and I strongly suspect that the context is important.
So, whilst you could create a new C# string with 33 null characters, what would be the point of that? Since the .net string is immutable, you cannot do very much of interest with it. In your VB6 code you will surely be mutating that object, and so StringBuilder is, in my view, the most likely tool for the job.
I believe you are looking for:
UserName = new String((Char)0, 33);
Reference this for what the VB6 method did.
You can create an function that perform this action, or o can do a extenssion of the class String.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(strGen("01",3));
}
//param s is the string that you can generete and the n param is the how many times.
private static string strGen(String s, int n){
string r = string.Empty;
for (int x = 1; x <= n; x++)
r += string.Copy(s);
return r;
}
}
I have spent the last day searching documentation, reviewing forum posts, and googling to try to do something that I am guessing could be easily done with the right information.
I have a very large existing C++ application that has an already defined COM server with many methods exposed. I am trying to use those COM methods in a C# application (I am experienced in C++, but a C# newbie).
So in my VS2010 C# application, I add the COM server as a reference. COM Methods are visible in the object browser, and passing single-valued strings, floats, and ints seems to work fine.
But I am stumped trying to read SAFEARRAY values passed out of the C++ COM server into the C# application. Eventually I need to pass string arrays from C++ server to the C# app, but in just testing passing an array of floats, I have code that builds but fails with the following exception when I try to cast the System.Object containing the array of floats to (float[]) ,
"exception {System.InvalidCastException: Unable to cast object of type 'System.Object[]' to type 'System.Single[]'."
With intellisence I can see that the Object contains the correct 8760 long array of floats, but I am unable to access that data in C#.
Here is the code on the C# side (d2RuleSet is an interface defined in the DOE2Com COM server). The exception above is thrown on the last line below.
DOE2ComLib.DOE2Com d2RuleSet;
d2RuleSet = new DOE2ComLib.DOE2Com();
System.Int32 i_Series =0;
System.Object pv_WeatherData;
float[] faWeatherData;
iOut = d2RuleSet.GetWeatherData(i_Series, out pv_WeatherData);
Type typeTest;
typeTest = pv_WeatherData.GetType();
int iArrayRank = typeTest.GetArrayRank();
Type typeElement = typeTest.GetElementType();
faWeatherData = (float[])pv_WeatherData;
Below is the section in the idl file defining the C++ COM method
HRESULT GetWeatherData( [in] int iSeries, [out] VARIANT* pvWeatherData, [out,retval] int * piErrorCode);
Below is the C++ code where the VARIANT data is loaded.
void CDOE2BaseClass::GetWeatherData( int iSeries, VARIANT* pvWeatherData, int* piErrorCode)
{
*piErrorCode = 0;
if (iSeries < 0 || iSeries >= D2CWS_NumSeries)
*piErrorCode = 1;
else if (m_faWeatherData[iSeries] == NULL)
*piErrorCode = 3;
else
{
SAFEARRAYBOUND rgsaBound;
rgsaBound.lLbound = 0;
rgsaBound.cElements = 8760;
// First lets create the SafeArrays (populated with VARIANTS to ensure compatibility with VB and Java)
SAFEARRAY* pSAData = SafeArrayCreate( VT_VARIANT, 1, &rgsaBound );
if( pSAData == NULL ) {
#ifndef _DOE2LIB
_com_issue_error( E_OUTOFMEMORY);
#else
//RW_TO_DO - Throw custom Lib-version exception
OurThrowDOE2LibException(-1,__FILE__,__LINE__,0,"OUT OF MEMORY");
#endif //_DOE2LIB
}
for (long hr=0; hr<8760; hr++)
{
COleVariant vHrResult( m_faWeatherData[iSeries][hr] );
SafeArrayPutElement( pSAData, &hr, vHrResult );
}
// Now that we have populated the SAFEARRAY, assign it to the VARIANT pointer that we are returning to the client.
V_VT( pvWeatherData ) = VT_ARRAY | VT_VARIANT;
V_ARRAY( pvWeatherData ) = pSAData;
}
}
Thanks in advance for help with this problem, I feel like I spent too much time on what should be a simple problem. Also please post up any links or books that that cover interop between native C++ and C# well (I think I have already ping-ponged through most of the Visual Studio/MSDN documentation, but maybe I missed something there too).
-----------------End Of Original Question------------------------------------------------------
I am editing to post the code from phoog's successful solution below, so others can read and use it.
int iOut = 0;
System.Int32 i_Series =0;
System.Object pv_WeatherData = null;
iOut = d2RuleSet.GetWeatherData(i_Series, out pv_WeatherData);
Type typeTest;
typeTest = pv_WeatherData.GetType();
int iArrayRank = typeTest.GetArrayRank();
Type typeElement = typeTest.GetElementType();
//float[] faWeatherData = (float[])pv_WeatherData;
float[] faWeatherData = ConvertTheArray((object[])pv_WeatherData);
....
float[] ConvertTheArray(object[] inputArray)
{
float[] result = new float[inputArray.Length];
for (var index = 0; index < result.Length; index++)
result[index] = (float)inputArray[index];
return result;
}
The marshalled SAFEARRAY is a System.Object[]; you can't reference-convert that to a System.Single[]. You have to cast the individual elements. This would work, assuming that all the elements of the argument array are in fact boxed floats:
float[] ConvertTheArray(object[] inputArray)
{
float[] result = new float[inputArray.Length];
for (var index = 0; index < result.Length; index++)
result[index] = (float)inputArray[index];
return result;
}
You could do that with a lot less typing using Linq, but as you're a C# newbie I thought a more basic solution might be better.
EDIT
Since you indicated in your comment that your object[] is referenced as an object, here's the usage example:
object obj = GetMarshalledArray();
float[] floats = ConvertTheArray((object[])obj);
EDIT 2
A shorter solution using Linq:
float[] ConvertTheArray(object[] inputArray)
{
return inputArray.Cast<float>().ToArray();
}