Optional function parameter with default value by reference - c#

By automatic conversion of code written in VB.NET to C# I have such situation in function declaration of VB.NET:
Private Function dataArchiver(ByVal toPlace As String,
Optional ByVal aExtension As String = ".7z",
Optional ByRef createdName As String = "") As Integer
Tool for automatic conversion does this in C#:
private int dataArchiver(string toPlace,
string aExtension = ".7z",
ref string createdName = "")
And this of course don't work. Keyword "ref" before last argument is underlined with red.
Why is that so? Because string createdName may be (and don't have to be) generated in function and in that case have to be passed out from function.
It is important that this code can work with NET framework 3.5.
Any idea to get this working in C# without much reconcepting of VB.NET program?

You have to create overloaded methods for this (as you would have had to do before C# acquired the optional parameter feature):
private int dataArchiver(string toPlace, string aExtension)
{
string tempVar = "";
return dataArchiver(toPlace, aExtension, ref tempVar);
}
private int dataArchiver(string toPlace)
{
string tempVar = "";
return dataArchiver(toPlace, ".7z", ref tempVar);
}
private int dataArchiver(string toPlace, string aExtension, ref string createdName)
{
return 0;
}

You can use the out keyword instead in this case:
string createdName;
int retVal = dataArchiver("to place", out createdName, extension);
And your new method signature.
private int dataArchiver(string toPlace,
out string createdName,
string aExtension = ".7z")
{
createdName = "some value";
// rest of your code
}
The only change is that out can't have a method signature default value, so you will need to set it inside the method.

Related

How to return the equivalent of a VB6 Variant type from a method in C#

I have an older VB6 app that has a function RunReturningVAR it is a db call that could return an int, string, double..... but not a RecordSet. It was built very generically so that it can be called by multiple other functions so we don't have multiple locations for DB calls.
what I currently have is attached.
Public Function RunReturningVar(ByVal vstrSql As String, _
Optional ByVal connval As Boolean = False, _
Optional ByVal copyID As Double = 0, _
Optional ByVal corpVal As Boolean = False, _
Optional ByVal vintConnectionTimeout As Integer = 30) As Variant
VB6 Variant (Can't believe I've found that link!) translates c# dynamic.
public dynamic RunReturningVar(
string vstrSql,
bool connval = false,
double copyID = 0,
bool corpVal = false,
int vintConnectionTimeout = 30)
{
// do your stuff here
}
It almost translates to object, but Variant is a data type specific for
late-binding, and it can hold reference types and value types - unlike c# object that can hold value types only through boxing.
Please note that working with dynamic means you bypass all the compile time type checks, which can result with run time errors you wouldn't normally expect from a c# program.
Perhaps you could do better with generics, but that would require you to specify the return type from the calling method:
public T RunReturningVar<T>(
string vstrSql,
bool connval = false,
double copyID = 0,
bool corpVal = false,
int vintConnectionTimeout = 30) where T : new()
{
// do your stuff here and return T
}
Also, For a public method in a public class, I would strongly suggest against using optional parameters in c#.
Use method overloading to specify default values.
The reason for that is the way optional parameters works in c#:
When a method with an optional parameter is being called, and the optional parameter is omitted, it's default value gets compiled into the method call.
So if you call to this method from another assembly, omitting some of the optional parameters - like this:
yourObjectReference.RunReturningVar(sql, true);
The c# compiler actually translate that to:
yourObjectReference.RunReturningVar(sql, true, 0, false, 30);
This means that if you ever want to change the default value of any of the parameters, other assemblies referencing this one should also be recompiled.
Therefor, a better alternative is to use method overloading:
public dynamic RunReturningVar(
string vstrSql,
bool connval,
double copyID,
bool corpVal,
int vintConnectionTimeout)
{
// do your stuff here
}
public dynamic RunReturningVar(
string vstrSql,
bool connval,
double copyID,
bool corpVal
)
{
return RunReturningVar(vstrSql, connval, copyID, corpVal, 30);
}
public dynamic RunReturningVar(
string vstrSql,
bool connval,
double copyID,
)
{
return RunReturningVar(vstrSql, connval, copyID, false);
}
and so on.

Pass by ref not working on convesion from vb.net to c#

I am trying to work out some code from a previous developer that was written in Vb.Net whereby he has created the following method which passes a string method ByRef as shown here:
Function prefixZeros(ByRef numberString As String, ByVal stringLength As Integer) As String
While numberString.Length < stringLength
numberString = "0" & numberString
End While
Return numberString
End Function
He subsequently calls it as follows:
Dim RandomClass As New Random()
Dim RandomNumber As Integer
RandomNumber = RandomClass.Next(0, 99999999)
Dim RandomString As String = prefixZeros(RandomNumber, 8)
and
Dim terminalId As String = System.Configuration.ConfigurationManager.AppSettings("terminalId").ToString()
terminalId = prefixZeros(terminalId, 8)
or
prefixZeros(DateTime.Now.Month, 2)
I am trying to replicate this code in C# but I have been unable to do thus far, on converting the prefixZeros method over I have the following:
public string prefixZeros(ref string numberString, int stringLength)
{
while (numberString.Length < stringLength)
{
numberString = "0" + numberString;
}
return numberString;
}
But If I attempt to call in it a similar fashion as:
Random RandomClass = new Random();
int RandomNumber = 0;
RandomNumber = RandomClass.Next(0, 999999999);
string RandomString = prefixZeros(RandomNumber, 9);
or
string terminalId = System.Configuration.ConfigurationManager.AppSettings["terminalId"].ToString();
terminalId = prefixZeros(terminalId, 8);
or
prefixZeros(DateTime.Now.Month, 2)
I am getting errors that there are some arguments which I can see is the types but I am not sure what I am supposed to be doing at this point, any help would be greatly appreciated
In C#, to pass a parameter as ref, you have to specify that at the call site as well as the method definition:
string RandomString = prefixZeros(ref RandomNumber, 9);
except... you can't do that because RandomNumber is an int and the function is expecting a string. Normally, in C# you might handle the type conversion like this:
string RandomString = prefixZeros(RandomNumber.ToString(), 9);
except that doesn't work with ref, because the result of ToString is just a temporary value! I'm guessing the VB code you're looking at does not have Option Strict On. Without that VB will automatically convert the number into a temporary string, and VB has no problem sending a temporary string into a ByRef parameter. On the other hand, C# will not allow a temporary value to be passed into a ref parameter. So you could do this:
string numberAsString = RandomNumber.ToString();
string RandomString = prefixZeros(ref numberAsString, 9);
and that will work for your method call.
Since your function returns the value that it's modifying, it doesn't really make sense to pass the parameter as ref anyway. This a common sort of sloppy coding that is allowed in VB but C# will be more strict about. And you don't want to be calling ToString everywhere, since it probably only makes sense to prefix zeroes to a number. So you should consider changing the function declaration to:
public string prefixZeros(int number, int stringLength)
But if you're converting a large code base from VB to C# you will want to check for calls that ignore the return value because they expect the parameter to be modified.
string RandomString = RandomClass.Next(0, 999999999).toString().PadLeft(9, '0');

convert ViewBag value into integer type

my ViewBag.searchid may contain either int value or string. If it contain string value like "this is mvc" the how will I convert that value in integer ?
[HttpPost]
public ActionResult SearchForEdit(string entryid)
{
ViewBag.searchid =entryid;
ViewBag.searchsong = entryid.ToString();
ViewBag.searchalbum = entryid.ToString();
return PartialView("SearchForEdit");
}
entryid value will get from textbox from viewpage. user can insert either id or string type value
try something like this
ViewBag.test = 13;
if (ViewBag.test is string)
{
//This is string
}
else if (ViewBag.test is Int32)
{
//this is integer
}
since ViewBag always contain dynamic datatype, so you can verify type of data at runtime.
object searchID = ...;
int numberResult = -1;
if (Int32.TryParse(searchID, numberResult))
{
//searchID is an int and stored in numberResult
}
else
{
//searchID is a string
//..saerchID.ToString();
}
You can't convert 'this is mvc' to an integer since its a string. The code above determines whether the searchID is convertible to a string or not.

VB to C# Code Translator

I am convering VB code to c#:
Private Function SoundsLike(ByVal pWord As String,
Optional ByRef pAccuracy As Byte = 6) As String.
But I got different type of parameters. Let me know how can I write in C#.
VB.Net
Private Function SoundsLike(ByVal pWord As String, Optional ByRef pAccuracy As Byte = 6) As String
C#
private string SoundsLike(string pWord, byte pAccuracy = 6)
{
}
private string SoundsLike(string pWord, out byte pAccuracy)
{
}
Note that out and ref cant have a default values
FYI : "The out keyword causes arguments to be passed by reference. This is similar to the ref keyword, except that ref requires that the variable be initialized before being passed."
Reference: http://geekswithblogs.net/ftom/archive/2008/09/10/c-and-the-difference-between-out-and-ref.aspx
The code like the following:
private string SoundsLike(string pWord, byte pAccuracy = 6);
requires C# 4.0 because contains optional parameters. For earlier version the same can be achieved via overload.
Use
private string SoundsLike(string pWord, byte pAccuracy = 6)
OR just
private string SoundsLike(string pWord, out byte pAccuracy)
Private is optional. If no modifier given, default is Private
void abc(){}
is same as
private void abc() {}
Same with variables.

C# Dll Invoke String Encoding Problem

StringBuilder codeline = new StringBuilder(100);
protected virtual int OnCodeLine(int code, int docId, ref StringBuilder codeline)
{
////
}
This is what i get with *ref StringBuilder*
ĞĞÑĞÒĞÓĞÔĞÕĞÖĞ×ĞØĞÙĞÚĞÛĞÜĞİĞŞĞßĞàĞáĞâĞãĞäĞåĞæĞçĞèĞéĞêĞëĞìĞíĞîĞïĞğĞñĞòĞóĞôĞõĞöĞ÷ĞøĞùĞúĞûĞüĞıĞşĞÿĞÑÑÑÑÑÑÑ Ñ
ÑÑÑ
ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
and only with StringBuilder i only get 3
This is what its suppose to return
300 078 9059431
By the way this the MICR Code from Cheques
[DllImport("mflib.dll")]
public static extern int mfScanFeeder(int mode, int font, int timeout);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int MFS100_CodeLineDelegate(int code, int docId, ref StringBuilder codeline);
public event MFS100_CodeLineDelegate MFS100_CodeLine;
private static MFS100_CodeLineDelegate cache_CodeLine;
Update : Here is the Original Code that works in vb6
Public Function MFS100_OnCodeline(ByVal code As Long, ByVal docId As Long, ByVal codeline As String) As Long
Dim i As Integer
WriteEvent "OnCodeline:"
WriteEvent " code = " & code
WriteEvent " docId = " & docId
WriteEvent " codeline = " & codeline
MFS100_OnCodeline = -1 ' -1 means: sorting will be done by mfSort()
g_codeline = codeline
CScannerForm.TmrSort.enabled = True
End Function
Update 2
mfSetEvent((int)EventEnum.E_EVENT_CODELINE, cache_CodeLine);
[DllImport("mflib.dll")]
private static extern int mfSetEvent(int eventID, Delegate callsback);
When i use StringBuilder with ref i get a string that have
32361 length. Without ref i get
only the first value of the
string.
OnCodeLine is for the callback
from the scanner device. What is the
problem ?
You should not pass the StringBuilder by ref. When you do that you say you only get one character back. That's the hallmark of expecting ANSI encoding but actually receiving Unicode (UTF-16). Fix it by specifying the character set:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet=CharSet.Unicode)]
public delegate int MFS100_CodeLineDelegate(int code, int docId, StringBuilder codeline);
I don't understand what are you trying to achieve, but if you want to collect a string generated inside OnCodeLine, you don't need to pass the StringBuilder by reference, as it is a reference type.
Just pass the StringBuilder without ref, populate it, and when you return you'll have the desired string in it.
Regarding what you get after calling the OnCodeLine, can you provide some info regarding the implementation?
Sorry, I didn't notice the PInvoke was involved!! :(

Categories

Resources