I found some code online. It is in C# and I am trying to port it to vb.net. I need some help with calling the evaluator function from within the Log subroutine. In C#, evaluator does not appear to expect any parameters when it gets called in Log. However, VB keeps asking for the Match parameter. What is the magic and how should I get it to work in VB.NET? Thanks.
private string evaluator(Match match)
{
Pri pri = new Pri(match.Groups[1].Value);
return pri.ToString()+" ";
}
private void Log(EndPoint endPoint, string strReceived)
{
...
string strMessage = string.Format("{0} : {1}",
endPoint, m_regex.Replace(strReceived, evaluator));
...
}
The C# version is using the (string, MatchEvaluator) overload of Regex.Replace(), and using the implicit conversion of the method name to the MatchEvaluator delegate type. See the MSDN documentation on that overload.
On the MSDN page, this is how they call it:
Dim result As String = rx.Replace(text, AddressOf RegExSample.CapText)
So make sure to use the AddressOf keyword.
Related
My situation: I'm creating a library using C# that will be called from Excel using VBA code. There's a C# method "SubscribeCallBack" which will receive an address of a VBA Procedure (Function Pointer) and marshal the function pointer into a C# delegate. Let me explain more:
In the C# library there's a variable to store a typed delegate:
public delegate bool TDelegate([MarshalAs(UnmanagedType.BStr)]string str);
TDelegate CallBack = null;
This delegate will run upon some event:
someObj.SomeEvent += (object sender, EventArgs args) => {
if (CallBack != null)
CallBack(someString);
};
And a method exposed to VBA code to set the CallBack:
public void SetCallBack(int callBackAddress) {
try {
CallBack = (TDelegate)Marshal.GetDelegateForFunctionPointer(
new IntPtr(address), typeof(TDelegate));
}
}
Now after the compiled C# library is loaded as a Excel AddIn, I can call C# methods using Application.Run(). I can write this:
Application.Run("SetCallBack", AddressOf VBACallBack)
Public Function VBACallBack(ByVal str As String) As Boolean
Cells(1, 1).Value = str
MsgBox "VBACallBack Running"
VBACallBack = True
End Function
Now things work as expected: I can see VBACallBack got executed when it should be.
Now finally comes the question: I put [MarshalAs(UnmanagedType.Bstr)]string as C# delegate parameter so that the VBA Function with a single string argument can be Marshaled to this typed delegate. Now I need to pass a Function from VBA like this into a C# delegate:
Function(stringArray() As String) As Boolean
taking a String array (or any other thing containing an ordered list of String to make it work)
How exactly can I do this? I tried with [MarshalAs(UnmanagedType.AsAny)]string[] and [MarshalAs(UnmanagedType.LPArray)]string[] both are not working.
I am working on PCL which along with a lot of functionality also provides log in. Also I recently started using delegates.
The Current Case:
I have a Simple methods that takes in parameters and provide GPlus, Facebook or Simple logIn with Username and Password. as in the code below:
public async Task<SignInResponse> SignInUsingFacebook(IFacebookInitializer faceBookConfiguration)
{
//my code
}
public async Task<SignInResponse> SignInUserNameAndPass(string username,string password)
{
//my code
}
public async Task<SignInResponse> SignInUsingGPlus(IGPlusInitializer gPlusConfiguration)
{
//my code
}
This is great, I can call them from my application directly and handle data but,
I recently came across Delegates and Func<T,TResult>
What I want to do:
I want a simple method that takes in a parameter an enum of LogInType as below:
public enum LogInType
{
UserNameAndPassword,
Facebook,
GooglePlus,
}
and based on the type of login type provided to the method, handles the LogIn process on it's own and just returns the SignInResponse object.
Is there a way this can be done using Delegates. Rather than having 3 individual methods to call for each case. If yes, then can someone please help in the parameters to be passed to the Single method along with The LogInType. I know it has to be a Func but what would the Func look like as it has to take 3 different parameters.
As From the Comments:
Each of those methods is a different signature anyway so you have a Func<IFacebookInitializer, Task<SignInResponse>>, Func<string, string, Task<SignInResponse>> and Func<IGPlusInitializer, Task<SignInResponse>> so you'd still end up with an if statement.
Can I return a Func when the method is called? this ways I can return either of the three func based on a quick switch case. The issue would be (if it's possible) what would be the generic response (or the common response) type of the method that returns either of these three methods
The generic Func works as follows:
The last datatype that you define in Func - "output" in this case should be the return type of the method which you are going to that particular function and the method should also be static.
This might help:
Func<LogInType, string> Login = LoginMethod;
private static string LoginMethod(LogInType loginType)
{
if (loginType == LogInType.Facebook)
return "Facebook";
if (loginType == LogInType.GooglePlus)
return "GooglePlus";
if (loginType == LogInType.UserNameAndPassword)
return "UserNameAndPassword";
return "Default";
}
The return type in the above example is string just for explaining.
My class requires additional information to properly output its status, so I've added a custom PrintSelf method taking the appropriate parameters.
However, I'm afraid there are still calls to ToString in my large project, which were not replaced by the new method. How can I find those improper calls to ToString?
I'm using VS 2015, but it does not seem to have this ability.
Throwing an exception in ToString would be an obvious way, but I don't want to do that for two reasons:
ToString can still perform a different job and output something not depending on the added parameter.
There is no way to get full code coverage, meaning it would only find a few instances of implicit calls, but not (reliably) all of them.
To override ToString and log the caller you can do like this
public override string ToString()
{
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
StackFrame callingFrame = stackFrames[1];
MethodInfo method = callingFrame.GetMethod();
YourLogingMethod(method.DeclaringType.Name + "." + method.Name);
return base.ToString();
}
You can make usage of the Obsolete Attribute :
public class MyFirstClass
{
//true or false parameters indicates whether to throw
// a compile error (true) or warning (false)
[Obsolete("Please use the method PrintSelf() instead of ToString()", false)]
public overrides string ToString()
{
//Whatever code you want here
return "";
}
}
public class MySecondClass
{
public void Test()
{
mfc = new MyFirstClass();
mfc.ToString(); //Here you will get a compiler warning
}
}
So this will let you know inside Visual Studio of all the calls made to this function. Since it is only a warning, it is still possible to use it.
(note : Sorry if the syntax is not correct, I'm normally a VB .Net developper, feel free to correct it if needed.)
New to C#. Is it possible to have delegates that point to the function that have "preset" argument that is set by me ?
public delegate void Del(string message);
static void Notify(string name)
{
Console.WriteLine("Notification received for: {0}", name);
}
// Looking for something similar, but code below gives me an error
// Del del5 = Notify("http://stackoverflow.com");
Sure - you can have lambda that call that function with whatever arguments you want. In your case us seem to ignore argument altogether which by convention is written as _ as argument name:
Del del5 = _ => Notify("http://stackoverflow.com");
del5("whatever - ignored anyway"); // always calls Notify("http://stackoverflow.com")
More genric case would be to have function with many (i.e.2) parameters and than specify first one to be fixed value in the delegate:
static void Notify2(string siteName, string message) {...}
Del messageToStackOverflow = message =>
Notify2 ("http://stackoverflow.com", message);
// calls Notify2 adding first argument SO:
// Notify2("http://stackoverflow.com", "Useful message to SO")
messageToStackOverflow("Useful message to SO");
In general this called partial function application when you fix some arguments to particular values.
No it is not possible to do it like this, because this would assign the result (void) of the Notify method call to del5. Default parameter values are not allowed for delegates.
I just started using C# this afternoon, so be a little gentle.
Currently I am working on a type of "template engine" where one of the callbacks needs to generate a globally unique ID. I am using delegates to manage the callbacks.
Currently the code looks like this (though I have also tried an anonymous function & returning NewGuid directly w/o a variable):
static string UID(List<string> p)
{
string s = Guid.NewGuid().ToString();
return s;
}
Which, when called directly, works fine. However if I try to call it via the delegate (added to a StringDictionary via addCallback("generate UID", new CallbackWrapper(UID))), the program will generate the same GUID regardless of how many times I duplicate it; even though calling the method directly both before & after the event occurs results in a unique ID as expected. I'v
No doubt it's just something simple I've missed, inevitably stemming from me being relatively inexperienced at C#.
Any help would be appreciated.
Thanks.
Well, I've now tried Dictionary with the same result.
CallbackWrapper is just the delegate, it's defined like this:
delegate string CallbackWrapper(List<string> parameters);
The remainder of the work is done in another class, which looks like this:
class TemplateParser
{
private Dictionary<string, CallbackWrapper> callbackMap;
public TemplateParser(string directivePrefix, string directiveSuffix)
{
...
callbackMap = new Dictionary<string,CallbackWrapper>();
}
public TemplateParser() : this("<!-- {", "} -->") {}
{
callbackMap.Add(name, callback);
}
public string parse(string filename)
{
...
string replacement =
callbackMap[directiveName](new List<string>(parameters.Split(new string[] { ";", " " }, StringSplitOptions.RemoveEmptyEntries));
...
}
}
I've stripped out the majority of the string handling code to save some space.
The issue is in your calling code, not in the code itself, nor in the delegate.
Using delegates here definitely works if called correctly.
Furthermore, your code can be slightly simplified:
static string UID(List<string> p)
{
return Guid.NewGuid().ToString();
}
(The variable is utterly redundant.)
use delegate.invoke
The difference between direct function call and delegate.invoke is here
http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/f629c34d-6523-433a-90b3-bb5d445c5587
StringDictionary will automatically cast your CallbackWrapper to a string, meaning it will only run once and store the output of CallbackWrapper.ToString(). This is probably not what you want.
Try using Dictionary<string, CallbackWrapper> instead.