Hey, how this is written in VB.NET? This was an example I found on http://www.codeproject.com/KB/silverlight/SynchronousSilverlight.aspx.
ThreadPool.QueueUserWorkItem(delegate
{
var channelFactory = new ChannelFactory<ISimpleService>("*");
var simpleService = channelFactory.CreateChannel();
var asyncResult = simpleService.BeginGetGreeting("Daniel", null, null);
string greeting = null;
try
{
greeting = simpleService.EndGetGreeting(asyncResult);
}
catch (Exception ex)
{
DisplayMessage(string.Format(
"Unable to communicate with server. {0} {1}",
ex.Message, ex.StackTrace));
}
DisplayGreeting(greeting);
});
May be a few syntax errors but I am sure you can resolve them.
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf GetGreeting))
Private Sub GetGreeting(o As Object)
Dim channelFactory = New ChannelFactory(Of ISimpleService)("*")
Dim simpleService = channelFactory.CreateChannel()
Dim asyncResult = simpleService.BeginGetGreeting("Daniel", Nothing, Nothing)
Dim greeting As String = Nothing
Begin Try
greeting = simpleService.EndGetGreeting(asyncResult)
Catch ex As Exception
DisplayMessage(String.Format("Unable to communicate with server. {0} {1}", ex.Message, ex.StackTrace))
End Try
DisplayGreeting(greeting)
End Sub
In VB10 (VS2010) you can do a rather literal translation:
ThreadPool.QueueUserWorkItem(
Sub()
Console.WriteLine("Hello")
End Sub)
And note that there are not linecontinuations (_) necessary here.
But you probably want this for VS2008 and then you need to break out the delegate as a separate Sub or Function.
Sub Main()
ThreadPool.QueueUserWorkItem(AddressOf CallBack, "Hello")
End Sub
Sub CallBack(ByVal state As Object)
Console.WriteLine(state)
End Sub
To provide a little explanation of the differences (other's have provided good code samples):
VB.NET doesn't support anonymous methods, which are supported in C# by using the delegate {} syntax to define an inline method. To convert that syntax to VB.NET you have to move the contents of the anonymous inline method out into a normal method, then use a Delegate pointed at the extracted method to initiate the call.
When both are compiled they are essentially the same, since anonymous methods in C# are really only anonymous in their pre-compiled state (the compiler generates names for the methods and then treats them as first-class methods).
Related
I am new to C# and I need to convert my code from VB.NET to C#.
Here is my VB.NET code
Private Sub Receive()
Dim inp As NetworkStream
Dim income As BinaryReader
inp = TCP.GetStream
income = New BinaryReader(inp)
While (State = "Connected")
Try
msg = income.ReadChar
Application.OpenForms(0).Invoke(New EventHandler(AddressOf prin))
Catch ex As Exception
Try
Me.Det = False
If TCpThread.IsAlive = True Then TCpThread.Abort()
TCP.Close()
msg = ex.Message
Catch ex1 As Exception
Application.OpenForms(0).Invoke(New EventHandler(AddressOf prin))
End Try
State = "IDLE"
End Try
End While
End Sub
Private Sub prin()
Message &= msg
Check(Message)
End Sub
It works fine, I converted it to:
private void Receive()
{
NetworkStream inp = default(NetworkStream);
BinaryReader income = default(BinaryReader);
inp = TCP.GetStream();
income = new BinaryReader(inp);
while (State == "Connected")
{
try
{
msg = System.Convert.ToString(income.ReadChar());
Application.OpenForms[0].Invoke(new EventHandler(prin));
}
catch (Exception ex)
{
try
{
this.Det = false;
if (TCpThread.IsAlive == true)
{
TCpThread.Abort();
}
TCP.Close();
msg = ex.Message;
}
catch (Exception)
{
Application.OpenForms[0].Invoke(new EventHandler(prin));
}
State = "IDLE";
}
}
}
private void prin()
{
Message += msg;
Check(Message);
}
But I get
Error 1 No overload for 'prin' matches delegate 'System.EventHandler'
for this line Application.OpenForms[0].Invoke(new EventHandler(prin));. Based on the multi-threading I need to invoke a function in order to follow my thread while it is running.
what is my mistake?
Any help will appreciate.
Use
Application.OpenForms[0].Invoke(new Action(prin));
The type EventHandler represents a delegate with two parameters (a generic object and an EventArgs object). Your method prin doesn't match that description.
If you just want to create a delegate for your method, use a delegate type that has the same arguments as your method (in this case none). In this case, this is the Action delegate.
The Action delegate should also have been used in the VB code in the first place:
Application.OpenForms(0).Invoke(New Action(AddressOf prin))
However, using EventHandler works in VB because the AddressOf operator in VB is not really type safe.
Here are some VB.NET code to C# conversions. Some work, some don't
Invoke(AddressOf prin) ' doesn't compile
Invoke(Sub() prin())
Invoke(New Action(AddressOf prin))
Invoke(New NoParameterVoid(AddressOf prin))
Invoke(New EventHandler(AddressOf prin)) ' doesn't compile with Option Strict On (original code)
' ...
Delegate Sub NoParameterVoid() ' required for 4th item
Invoke(prin); // doesn't compile
Invoke(() => prin()); // doesn't compile
Invoke(new Action(prin));
Invoke(new NoParameterVoid(prin));
Invoke(new EventHandler(prin)); // doesn't compile
// ...
delegate void NoParameterVoid(); // required for 4th item
So the only two which are directly convertible to C# code which compiles are
Invoke(New Action(AddressOf prin))
Invoke(New NoParameterVoid(AddressOf prin))
and since the Delegate Sub NoParameterVoid() we need to create is identical to Action(), there's no point in creating it, in my opinion. So the only reasonable option, when trying to convert directly to c#, is:
Invoke(New Action(AddressOf prin))
Invoke(new Action(prin));
This might not have been a question if you had Option Strict On to begin with; you may have come up with Action() on your own.
So I have the following code in C#:
public Container ConfigureSimpleInjector(IAppBuilder app)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.RegisterPackages();
app.Use(async (context, next) =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
await next();
}
});
container.Verify();
return container;
}
The app.Use() is defined as Owin.AppBuilderUserExtensions.Use() and looks like this:
public static IAppBuilder Use(this IAppBuilder app, Func<IOwinContext, Func<Task>, Task> handler);
The VB equivalent is as follows:
Public Function ConfigureSimpleInjector(app As IAppBuilder) As Container
Dim container = New Container()
container.Options.DefaultScopedLifestyle = New AsyncScopedLifestyle()
container.RegisterPackages()
app.Use(Async Sub(context, [next])
Using AsyncScopedLifestyle.BeginScope(container)
Await [next]()
End Using
End Sub)
container.Verify()
Return container
End Function
For some reason, in the VB version, the app.Use() doesn't use the extension function that's available and simply uses IAppBuilder.Use() instead, as follows:
Function Use(middleware As Object, ParamArray args() As Object) As IAppBuilder
Why does the VB code not use the same extension function that C# does and how can I make it use that?
Edit
For clarity, the extension methods are not my own. They are from the Owin 3rd party library. So there is no option of renaming the extension methods.
In the C# code because next is Func and await returns a task, there is no return statement, but actualy a Task object is returned.
IMO the VB.NET code does not return a Task object, because the lambda is specified as Sub (= Action in C#).
Changing the Sub to Func in the VB.NET code should call the wanted method.
In VB (fiddle), you can pass a lambda expression when an object is required:
Public Shared Sub Main()
MyMethod(Function() True) ' compiles
End Sub
Public Shared Sub MyMethod(o As Object)
End Sub
In C# (fiddle), that doesn't work:
public static void Main()
{
// Compilation error: Cannot convert lambda expression to type 'object' because it is not a delegate type.
// You'd need to use: MyMethod(new Func<bool>(() => true));
MyMethod(() => true);
}
public static void MyMethod(object o) { }
This is probably due to the fact that lambda expressions can be implicitly converted to delegates in VB but not in C#:
' Compiles
Dim d As System.Delegate = Function() True
// Compilation error: Cannot convert lambda expression to type 'Delegate' because it is not a delegate type
System.Delegate d = () => true;
Thus, in your code example, VB finds a matching suitable instance method and uses it. In the C# code, no matching instance method is found (since your lambda expression does not match object), and the extension method is used instead.
Note that both languages prefer instance methods over extension methods if a matching method is found. This can lead to subtle bugs if a matching instance method is added later.
How to fix that? I suggest to use different names for the extension method and the instance method - other developers reading your code in the future will thank you for it. If that's not an option, you can always call the extension method explicitly:
Owin.AppBuilderUserExtensions.Use(app, Async Sub(context, [next]) ...)
I have this code on different thread:
string sub = "";
this.BeginInvoke((Action)(delegate()
{
try
{
sub = LISTVIEW.Items[x].Text.Trim();
}
catch
{
}
}));
MessageBox.Show(sub);
what I want is to get the value of "LISTVIEW.Items[x].Text.Trim();" and pass it to "sub". please note that the LISTVIEW control is on the main thread. now how can I accomplish this?
enter code here
Func<string> foo = () =>
{
try
{
return LISTVIEW.Items[x].Text.Trim();
}
catch
{
// this is the diaper anti-pattern... fix it by adding logging and/or making the code in the try block not throw
return String.Empty;
}
};
var ar = this.BeginInvoke(foo);
string sub = (string)this.EndInvoke(ar);
You, of course, need to be a bit careful with EndInvoke because it can cause deadlocks.
if you prefer delegate syntax you can also change
this.BeginInvoke((Action)(delegate()
to
this.BeginInvoke((Func<String>)(delegate()
you stll need to return something from all branches and call end invoke.
I have an Excel add-in with a class module. I want to instantiate the class module in C# and call a method on it. How do I do that?
If you really need access to an instance of the class, you could do the following:
Generate a type library for a COM interface that you want to expose from your VBA class (e.g. IMyComInterface)
Add a reference to this type library in your VBA project
Implement the interface in your VBA class module - e.g. MyVbaClass (use the Implements keyword):
Option Explicit
Implements IMyComInterface
Private Sub IMyComInterface_SomeMethod(...)
...
End Sub
...
Reference the same type library in your C# project
Create a ComVisible C# class with a method that accepts a reference to the VBA interface instance. Something like:
public class MyVbaLoader
{
public IMyComInterface MyComInterface
{
get { return myComInterface; }
set { myComInterface = value; }
}
}
Write a "factory" method in a VBA standard module, that takes an object as a ByRef parameter. This object should assume the object passed as an argument has a property "MyComInterface" and should set this property to a new instance of the VBA class MyClass.
Public Sub MyFactoryMethod(MyVbaLoader As Object)
Dim objClass As MyVbaClass
Set objClass = New MyVbaClass
... any initialization of objClass here ...
' Pass a reference to the VBA class to the C# object MyVbaLoader
MyVbaLoader.MyComInterface = objClass
End Sub
Call the factory method from your C# code. Assuming you have opened the workbook and have a refence "workbook" in your VBA code, the code will look something like:
MyVbaLoader loader = new MyVbaLoader();
workbook.Application.Run("MyModule.MyFactoryMethod", loader, Type.Missing, ... , Type.Missing);
// we now have a reference to the VBA class module in loader.MyComInterface
// ...
As you can see, it's rather complex. Without more detail of the problem you're trying to solve it's difficult to say whether this complexity is justified, or whether there's a simpler solution.
If the above isn't clear, let me know and I'll try to clarify.
Basically you can't return a value from a VBA macro called from your C# code using Application.Run, so you have to resort to passing an object by value that has a method or property that can be called from VBA to set the instance.
VBA class modules have only two instancing modes: private, and public-not-creatable. So, you can't even instantiate them in another VB(A) project, let alone from C#.
However, there's nothing to stop you having a standard module that acts as a class factory. So, if your class module is Foo then you can have a method in a standard module called NewFoo that instantiates a new Foo for you and returns it to the caller. The Foo object would obviously have to be public-not-creatable.
[Your NewFoo method can take parameters, so you can simulate parameterized constructors, which aren't available in VBA.]
EDIT: detail on how to call VBA function (in a standard module) from C# and get the return value using Application.Run.
private static object RunMacro(Excel.Application excelApp, string macroName, object[] parameters)
{
Type applicationType = excelApp.GetType();
ArrayList arguments = new ArrayList();
arguments.Add(macroName);
if (parameters != null)
arguments.AddRange(parameters);
try
{
return applicationType.InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, excelApp, arguments.ToArray());
}
catch (TargetInvocationException ex)
{
COMException comException = ex.InnerException as COMException;
if (comException != null)
{
// These errors are raised by Excel if the macro does not exist
if ( (comException.ErrorCode == -2146827284)
|| (comException.ErrorCode == 1004))
throw new ApplicationException(string.Format("The macro '{0}' does not exist.", macroName), ex);
}
throw ex;
}
}
Note that you could omit all that try...catch stuff - all it's doing is handling the specific error where the macro does not exist and raising a more meaningful exception in that case.
The object returned from the function can be cast to whatever type you need. For example:
object o = RunMacro(excelApp, "MyModule.MyFunc", new object[] { "param1", 2 });
if (o is string)
{
string s = (string) o;
Console.WriteLine(s);
}
Assuming that the function actually returns an instance of your VBA-defined class object, then you can call the methods of that object in the same way, again using InvokeMember:
object o = RunMacro(excelApp, "MyModule.MyFunc", new object[] { "param1", 2 });
// assume o is an instance of your class, and that it has a method called Test that takes no arguments
o.GetType().InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, o, new string[] {"Test"});
If you're doing a lot of these calls, then obviously you can hide the ugly detail by creating wrapper methods to make the call for you.
Please note that I've typed most of this from memory, so I fully expect there to be syntax, logical and possibly even factual errors :-)
I have a function that calls out a read or write request on a serial port and then returns the value that was read. I am using Commstudio express (I'm implementing a class from Commstudio) , but it's timeout features don't appear to work at all, so I'm trying to implement my own timeout. Currently I have a timer that is set upon request to read or write to the port, and if the timer goes off, the callback closes the connection causing an exception. I tried to have the callback of the timer throw an exception, but the exception needs to be propagated up through the thread that was calling the original read/write function, so in this way, it works, but I feel like it's messy and there must be a better way to do what I want.
Here is a generic solution that allows you to wrap any method in a timeout:
http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time/
It uses the useful Thread.Join overload that accepts a timeout in milliseconds rather than manually using timers. The only thing I would do differently is swap the success flag and result value to match the TryParse pattern, as follows:
public static T Execute<T>(Func<T> func, int timeout)
{
T result;
TryExecute(func, timeout, out result);
return result;
}
public static bool TryExecute<T>(Func<T> func, int timeout, out T result)
{
var t = default(T);
var thread = new Thread(() => t = func());
thread.Start();
var completed = thread.Join(timeout);
if (!completed) thread.Abort();
result = t;
return completed;
}
And this is how you would use it:
var func = new Func<string>(() =>
{
Thread.Sleep(200);
return "success";
});
string result;
Debug.Assert(!TryExecute(func, 100, out result));
Debug.Assert(result == null);
Debug.Assert(TryExecute(func, 300, out result));
Debug.Assert(result == "success");
You could also add overloads that accept Action instead of Func if you want to execute a method that doesn't return a value.
Sounds like you're doing a blocking read/write. What you want to do is a non-blocking read/write.
There is probably a way to tell the com port that you're wanting non- blocking.
Are you sure the timeouts are not working with commstudio? maybe you have to do something special to initialise them.
In any case, you want to read as much data as possible and if none is available time out (depending on what the value of the time out is). You'll want to keep looping while no data available and no error and then return a time out condition if there wasn't anything available.
Make your read function return an integer. negative values = error value e.g. -1 = timeout, positive number of bytes read... at least thats the way I'd do it.
You can create an extension method that takes the Task<T> and a defaultValue of type T as input. Here is my implementation.
public static class Helpers
{
public static Task<T> SetTimeout<T>(this Task<T> task, T defaultValue, int timeoutInMilliseconds = 1000)
{
var timeout = Task.Delay(timeoutInMilliseconds);
Task.WaitAny(task, timeout);
if (!task.IsCompleted)
return Task.FromResult(defaultValue);
return task;
}
}
Here is a usage example:
var cars = await _myService.GetCars().SetTimeout(new List<string>() { "Toyota", "Nissan" });
For the comport you could just test if there is anything available and then do a read instead of doing a blocking read without knowing there is something yet. Something like:
Int32 timeout=1000;
String result = String.Empty';
while (timeout!=0) {
if (Serial.BytesToRead>0) {
while (Serial.BytesToRead>0) {
result+=Serial.ReadChar();
}
break;
}
Thread.Sleep(1);
timeout--;
}
In case someone wants to do this in VB.Net, don't listen to those who say it can't be done!
You may need to alter your generic parameters to suit your use case.
Public Shared Function Execute(Of I, R)(Func As Func(Of I, R), Input As I, TimeOut As Integer) As R
Dim Result As R
TryExecute(Func, Input, TimeOut, Result)
Return Result
End Function
Public Shared Function TryExecute(Of I, R)(Func As Func(Of I, R), Input As I, TimeOut As Integer, ByRef Result As R) As Boolean
Dim OutParam As R = Nothing
Dim Thread As New System.Threading.Thread(Sub() InlineAssignHelper(OutParam, Func(Input)))
Thread.IsBackground = True
Thread.Start()
Dim Completed As Boolean = Thread.Join(TimeOut)
If Not Completed Then Thread.Abort()
Result = OutParam
Return Completed
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef Target As T, ByVal Value As T) As T
Target = Value
Return Value
End Function
And an example of how to use it (mine was with Regex.Match, which sometimes goes off into never never land if the patterns contains too many wild cards:
Public Function Match(Input As String) As Match
If Regex Is Nothing Then Return Nothing
Dim RegexMatch As System.Text.RegularExpressions.Match = Nothing
Dim Func As New Func(Of String, System.Text.RegularExpressions.Match)(Function(x As String) Regex.Match(x))
If Runtime.TryExecute(Of String, System.Text.RegularExpressions.Match)(Func, Input, 2000, RegexMatch) Then
Return (New Match(Me, Regex.Match(Input), Input))
Else
Return Nothing
End If
End Function