Ran into an interesting problem that I was wondering if anyone can help explain. I have tried searching all over the internet and can’t seem to find an answer to this problem. While we have a solution, others might run into the same problem, and since it was random, it is very hard to track down.
We have an application that randomly fails when the computer is attached to the customers corporate network (don’t have a lot of information on the network). When we brought the computer to our environment it worked fine. The failure is fairly random, but as best as I could figure out occurred during calls from C# to an unmanaged third party vendors DLL. One of the trace backs I do have (only a couple failures provided traces in the system event log) points to a failure in ntdll.dll in the RtlMoveMemory function during the marshalling of parameters in calls to the unmanaged DLL.
The call to the unmanaged function was:
ThirdParty.CxxxAutomationWrapper clientDLL = new ThirdParty.CxxxAutomationWrapper () ;
object Parameter1 ;
:
string theValue = "abcde" ;
Parameter1 = theValue ;
:
if ( Parameter1 is string )
{
int returnCode = clientDLL.function ( Parameter1 as string ) ;
}
The call periodically fails on the customers computer but always works when run within Visual Studio (2010). The value of Parameter1 is correctly set (never null).
Since I changed the call to:
String parameter1String = Parameter1.ToString() ;
int returnCode = clientDLL.function ( parameter1String ) ;
everything has worked fine. The value of Parameter1 is very controlled and is not null prior to this code being executed.
The interface being called (clientDLL.function) is defined as:
HRESULT function ( [in] BSTR parameter,
[out, retval] long *ret);
With my [limited?] understanding of the ‘as’ statement in c#, I don’t understand why the first version of this failed. Can anybody help explain why this fails when called with the parameter specified as “as string”?
Because obj as string and obj.ToString() are not the same. The first is an attempted cast (sort of like (string)obj, but which returns null upon failure), while the seconds is a method call returning a string representation of the object.
Practically you can get the string representation of any object regardless of whether it's compatible with string as type, but the cast will fail if they are not compatible.
Simple example:
object obj = new object(); // simple object
Console.WriteLine(obj.ToString()); // prints System.Object
Console.WriteLine((obj as string) == null); // True: obj is not a string!
Parameter1.ToString() will render any .NET object to a string (i.e. instance of System.String). Parameter1 as string will return null if Parameter1 is null or if it is not an instance of System.String. If it is a class that wraps a string rather than actually being one, then you will end up with a null.
Neither will work in every case of course. If you have an instance of System.String which is null, then Parameter1 as string would correctly return null, whereas Parameter1.ToString() would throw a NullReferenceException.
A safe approach would be: Convert.ToString(Parameter1).
Parameter1 as string could be thought as
string foo
try
{
foo = (string)Parameter1;
}
catch
{
foo = null;
}
where .ToString() is
string foo = Parameter1.ToString();
The fact that Parameter1 is not directly castable to a string is the reson for it failing.
Related
I am new to c# and a little confused about how the out parameter modifier works.
I have this function
public static void GuidUnsmash(string smashed, out Guid first, out Guid second)
{
if (smashed.Length != 64)
{
throw new ArgumentOutOfRangeException();
}
string firstGuid = smashed.Substring(0, 32);
string secondGuid = smashed.Substring(32, 32);
first = new System.Guid(firstGuid);
second = new System.Guid(secondGuid);
}
which im trying to call using this
[HttpGet]
public async Task<ActionResult> Pending(string pendingticket)
{
// CAR-AAR built with PersonId and MonerisID in ticket, this was overkill, just needed the MonerisID
GuidHelpers.GuidUnsmash(pendingticket, out Guid personId, out Guid monerisId); //this is the line that has the error
var preload = await MonerisApplicationRepository.PrepareTransactionForMonerisPreload(monerisId);
var preloadResponse = await MonerisRepository.PostPreloadTransactionRequest(preload);
var persistPreload = await MonerisApplicationRepository.PersistMonerisPreloadTransactionResponse(monerisId, preloadResponse);
var transactionRequest = preloadResponse.ToMonerisPreAuthorization();
//var viewPendingRequest = new MonerisPendingPreloadTransaction(transactionRequest, preload);
// View redirects to Moneris with autosubmit to begin preauthorization process.
return View(transactionRequest);
}
However i am getting an error that says that there is no overload method for GuidUnsmash. Which is confusing me because they both have the same amount of parameters.
Normally, parameters used in function calls are "passed-by-value". The other option is for parameters to be passed-by-reference.
Keyword ref forces a parameter to be passed-by-reference. But that does not mean the function will actually do anything with the variable. It may or it may not.
Keyword out forces a parameter to be passed-by-reference and also that the value has to be assigned in the function. This can have ramifications for stuff like readonly variables which need a assignment. And so the caller is aware the value will not stay the same.
Keyword in is relatively new syntax, related to 'ref' and 'out'. It forces a parameter to be passed-by-reference but also prevents any reassignment of the value (like a inverted out). However I am somewhat unsure why you would use it.
In langauges that use naked pointers, usually naked pointer is used instead of ref. And there are no in or out keywords.
As for overloading:
The in, ref, and out keywords are not considered part of the
method signature for the purpose of overload resolution. Therefore,
methods cannot be overloaded if the only difference is that one method
takes a ref or in argument and the other takes an out argument.
Which means the error make no real sense.
So that leaves one hard-to-debug issue: the code is so broken somewhere before or between those two code piece, the compiler has issues even still telling you where the error is.
Some context first :
I was writing a reusable "null tester" method that will be used to check if any variable of an object has a null or empty value. the goal is that the method can take an Object and use reflexion to check the value of each property.
Everything worked until I added a List<string> to a class that is being checked.
While adding List<string> raised the TargetParameterCountException other primitive types didn't. The only other time I managed to reproduce this error is when I passed directly a string.
I managed to boil down this problem to that bit of code :
string toCheck = "foo";
var elementProperties = toCheck.GetType().GetProperties();
foreach (PropertyInfo property in elementProperties)
{
var elementValue = property.GetValue(toCheck);
//Check if "toCheck" is null or empty here
}
elementProperties has two Values
An Int32 Length
A Char Chars[Int32]
My understanding would be that the first represent the length and the second the content of the string. But when the code tries to "GetValue()" the second property it raises a TargetParameterCountException.
Does someone know why it would do that ?
since I was trying to access a char array I needed to specify the index of which char I want to retrieve.
using :
property.GetValue(toCheck, new object[] {index})
Pardon me,I am not very good in explaining questions.
I can better explain my question through following example:
string first = "hello";
string second = "Bye";
first = second;
In the above example,consider the third line first=second .
Here i assigned object second to first. Because strings in c# are immutable i.e Every time you assign a new value to an existing string object, a new object is being created and old object is being released by the CLR.(I read this from here1).
So simply it means the object first in first line is different from object first in third line.
So My question is how can i prove both are different?
i.e if it(string) is possible in C then i can print address of both objects before and after the third statement to prove it.
Is there any method to access there addresses or other alternatives are there?
If you'd like to see the physical location in memory, you can use the following (unsafe) code.
private static void Main(string[] args)
{
unsafe
{
string first = "hello";
fixed (char* p = first)
{
Console.WriteLine("Address of first: {0}", ((int)p).ToString());
}
string second = "Bye";
fixed (char* p = second)
{
Console.WriteLine("Address of second: {0}", ((int)p).ToString());
}
first = second;
fixed (char* p = first)
{
Console.WriteLine("Address of first: {0}", ((int)p).ToString());
}
}
}
Sample output on my machine:
Address of first: 41793976
Address of second: 41794056
Address of first: 41794056
You'll notice, that .NET caches the string instances which is perfectly valid because they are immutable. To demonstrate this behavior, you can change second to hello and all memory addresses will be the same. That's why you shouldn't rely on native memory stuff and just use the managed ways to work with objects.
See also:
The common language runtime conserves string storage by maintaining a
table, called the intern pool, that contains a single reference to
each unique literal string declared or created programmatically in
your program. Consequently, an instance of a literal string with a
particular value only exists once in the system.
Source: String.Intern (MSDN)
I believe that you want the ReferenceEquals method. It can be used to check if two instances of the object are exactly the same - i.e. references the same object.
*you can use the .Equals() method or HashCode() method to compare *
If you have to compare the underlying memory addreses, the following unsafe code might help you (untested):
string first = "hello";
GCHandle handle = GCHandle.Alloc(first, GCHandleType.Pinned);
IntPtr address = handle.AddrOfPinnedObject();
string second = "Bye";
first = second;
GCHandle handle = GCHandle.Alloc(first, GCHandleType.Pinned);
IntPtr address2 = handle.AddrOfPinnedObject();
if (address != address2)
{
// memory addresses are different afterwards
}
for this you should get memory address of first first variable before assigning second to it and again check the memory address after assigning.
for getting the address of string follow this link
may this help you
You've misunderstood what you've read. Yes, strings are immutable. That means you cannot change an existing string. This won't work:
string x = "Hello";
x[3] = 'q';
When you're concatenating strings, you get a new one:
string a = "a";
string b = "b";
string c = a+b; // You get a new string and a and b are unchanged.
Even when you're self-concatenating, you get a new string:
string a = "a";
a += "b"; // The same as a = a + "b" and yields a new string.
But assigning to a variable (or passing to a function, or returning from a function, etc) does NOT create a new string.
Strings are "reference types". That means that this variable:
string a = "Hello";
Is just a reference to the string. Doing this:
string b = a;
Just assigns the reference to the variable. It does not alter the string.
Or, to put it in C terms: Reference variables are pointers to objects. Consider:
string a = "Hello"; // a now points to the string object
string b = a; // b now points to the same object.
What the immutability means is that you cannot change the memory that the pointer points to (the string object itself). But the pointer variable is as changeable as ever. You can assign a different address to it.
To return to your original example:
string first = "hello"; // Allocates memory for "hello" and points first to it.
string second = "Bye"; // Allocates memory for "Bye" and points second to it.
first = second; // Assigns the address of second to first.
In the end, both first and second point to the same address, which is the address of the string Bye. The memory of the string hello is now unreferenced (there are no pointers to it, it's unreachable). The garbage collector will reclaim it sometime later.
Added: Yet another analogy with C. String variables .NET are somewhat like this:
const char* str;
It's a pointer to a constant. You can change the pointer, but you cannot change the stuff that it points to.
Added 2: You should read up on Value Types vs Reference Types in .NET. In a nutshell, value types are all struct types, and reference types are all class types. Value types get copied on assignment (or when passed/returned from a function); reference types are pointers.
Note that there is one unintuitive piece here. The class object, which is the base class of ALL types, is a reference type. Yet Value Types inherit from it, and you can assign a Value Type to a variable of type object. If you do it, this will cause something called boxing and it involves making a copy of the value, so it's a bit of an expensive operation.
I have encountered some unforeseen consequences of porting to mono 2.8.1. Problem can be boiled down to a sample program (I have been unable to reduce it further, after cutting several classes and ~1000 lines of code to the file quoted below)
public class Person
{
public Person(int age, string name = null){}
public Person(double income, string name = null){}
public Person(double income, int age, string name = null){}
}
class Program
{
static void Main()
{
Person p = new Person(1.0, name: "John Doe");
}
}
Compilation of above code with mcs gives output:
test.cs(22,24): error CS0584: Internal compiler error: Internal error
test.cs(22,20): error CS0266: Cannot implicitly convert type `object' to `NamedParams.Person'.
An explicit conversion exists (are you missing a cast?)
Compilation failed: 2 error(s), 0 warnings
Removing use of optional/named parameter (i.e. calling new Person(1.0, null, "John Doe") or new Person(1.0, null, name:"John Doe"), or new Person(1.0, "John Doe") ) leads to flawless compilation. Also, under VS2010 the file (and whole solution with which I started with) compiles fine. Casting removes error CS0266, but not CS0584 -- so no surprise there.
My question: is it me doing something wrong, or mcs (i.e. bug in mcs is obvious to me -- what else ,,internal error'' would mean, but perhaps it's ok such program won't compile), or maybe Microsoft compiler in VS2010 should not let such code to compile?
I bet it's mcs who's wrong (unable to guess right constructor), but perhaps it's otherwise and I shouldn't know better?
PS. I tried searching for a known bug like this in both Google and Novell's Bugzilla, but was unable to find anything relevant. Again, I may be blind ;)
Okay, here goes. The crash is indeed due to the third overload, Person(double income, int age, string name = null).
The compiler sees you are trying to pass less arguments than what are listed in the signature so it goes looking for optional arguments. It happily notices that name is optional and assumes you are not passing that argument. It does this by appending a placeholder at the end of the supplied arguments. Next, it goes to reorder the named arguments in the list so they end up in their right position. This means John Doe is now correctly at the last position for name, but the placeholder gets into the age position. The compiler then tries to fill in the default values, but is shocked to find a placeholder at a location which has no default value. It thinks this can not happen, since the placeholder was only added for an optional argument and now suddenly it is not optional anymore. Not knowing what to do, it throws an exception.
The following patch seems to fix the issue (however it may break something else, so no warranty):
--- mono-2.6.7.orig/mcs/mcs/ecore.cs 2009-10-02 12:51:12.000000000 +0200
+++ mono-2.6.7/mcs/mcs/ecore.cs 2010-12-21 02:26:44.000000000 +0100
## -3803,6 +3803,15 ##
int args_gap = Math.Abs (arg_count - param_count);
if (optional_count != 0) {
+ // readjust for optional arguments passed as named arguments
+ for (int i = 0; i < arguments.Count; i++) {
+ NamedArgument na = arguments[i] as NamedArgument;
+ if (na == null)
+ continue;
+ int index = pd.GetParameterIndexByName (na.Name.Value);
+ if (pd.FixedParameters[index].HasDefaultValue)
+ optional_count--;
+ }
if (args_gap > optional_count)
return int.MaxValue - 10000 + args_gap - optional_count;
For others coming to this thread. The bug is still there in the latest versions of Mono Compiler as of April 2013. I created a work around without needing to modify the compiler using C# overloaded functions.
Foo(int a, bool b = true) {
Foo(a, b, "Default String");
}
Foo(int a, bool b, string c)
I'm using some old code that runs a sql query as a reference.
At some point, it gets to something like:
sqlDataAdapter.Fill(dataSet);
DataRow dataRow = dataSet.Tables[0].Rows[0];
Object obj = dataRow[fieldName];
The old code does:
string output;
if (!string.IsNullOrEmpty(obj.ToString())) { output = obj.ToString(); }
else { output = "Not Available"; }
I changed them to:
output = obj as string ?? "Not Available"
But sometimes, it broke. As I suspected, it was happening breaking when the entry was an int. Casting as an int in those cases solved that problem.
Then another problem arose when there was no entry for obj[fieldName] of type int. When I stepped through the debugger, I was surprised to find that obj wasn't null. In VS, mousing over revealed it had a value {}.
What the heck is {}? How do I make a boolean test of it?
(In the old code, it appears .ToString() returns "" in this case and works as expected.)
{ and } are opening and closing braces and symbolic of the start and finish of an object. Hence an empty object with no special properties is depicted in shorthand as {}. The debugger uses this notation to help you visually distinguish between an empty object, an empty string and null.
If you hover over obj[fieldName] and there is no entry for fieldName, the debugger won't care about that, it'll show the value of obj. You'll have to use the immediate window or a watch/quickwatch. The debugger will only see you hovering over obj and assume you're referring to the array itself, not the contents of the array at the specified index.
In case anyone comes across again this problem.
Solution if val object is shown {} in debug mode
// Check if its not null or empty
if (!IsNullOrEmpty(val.ToString().ToArray()))
{
// Do something with val
dt.Rows.Add(val);
}
public static bool IsNullOrEmpty<T>(T[] array)
{
return array == null || array.Length == 0;
}