So I'm just a uni student who's enjoying programming (1st year) and I've decided to try out some new features.
I came across the speech synthesizer and its reallt interesting, but i have one problem.
Say if I said
Console.WriteLine("Hello");
Is there a way that I could get the program to say that without having to add
Console.WriteLine("Hello");
s.Speak("Hello");
?
Like I'm wondering if I am able to have my program speak whatever I type without adding extra code
Cheers
There is no way you could do that. But what you can try is creating a static method that takes a string value and prints "Hello" on to the console and use the TTS engine, like
static void PrintAndSpeak(string message)
{
Console.WriteLine(message);
s.Speak(message);
}
And then use the method inside the entry point:
PrintAndSpeak("Hello");
You could create a method that would take in your string. That method would print and read the message.
Example (pseudocode)
public void writeAndTalk(string message){
Console.WriteLine(message);
s.Speak(message);
}
And you then use the method wherever you like.
You could create a type to do this for you. Something like:
public class TextAndSpeech
{
private readonly WhateverSIs s;
public TextAndSpeech(WhateverSIs s)
{
this.s = s;
}
public Spurt(string message)
{
Console.WriteLine(message);
s.Speak(message);
}
}
I have no idea what type s is that you're using, so replace WhateverSIs with the actual type.
Using it would look something like:
var spurter = new TextAndSpeech(new WhateverSIs());
spurter.Spurt("Hello");
spurter.Spurt("Another thing.");
Related
I just learned about delegates and the publisher/subscriber pattern, however I have been having some problem implementing them in my current code, mainly because Im not sure what should be assign to what(I shall explain this).
I have a class, example Class A. It is a library class that contains codes that write logs into .txt file. I would like to be able to take these logs and write them somewhere else, example another .txt file/TextBox/RichTextBox.
Class A
//Just a library class for log functions
//Declare and instantiate the delegate
public void delegate myDel(string message)
public myDel customDel, customDel2
LogCategory(string category)
{
//Bunch of codes that separates the log into category Info/Warn/Error
WriteLog()
}
WriteLog()
{
StreamWriter sw = new StreamWriter(LogFilePath)
//writes logs into .txt file1
}
then in a separate class
Class B
//This is the main program where all the logs are written
public void PrintLog(string message)
{
Class A ca = new Class A();
ca.LogCategory();
}
public void delegateTheLogs()
{
//how do I use customDel to write the logs to another text file in a
//different directory
}
The idea is that delegate is suppose to:
act as a pointer
allow the program to write logs to multiple destination at the same time
The question is what do I use customDel for and how do I use it catch the logs and write them somewhere?
I think this is an interesting topic, and if anyone knows how to do this, please help me figure this out.
Oh and Im not interested in using events, I know delegate and events are pretty common to use together.
Thanks
Following on from my comment, here's an example. We have a class called FlexibleLogger that basically knows how to format stuff that it is given but it doesn't have any baked in ability to write the log data to anywhere, the idea being that the code that creates the logger also creates the routine that the logger will use to output:
public class FlexibleLogger{
Action<string> _logWriterAction;
public FlexibleLogger(Action<string> logWriterAction){
_logWriterAction = logWriterAction;
}
public Log(string message){
_logWriterAction($"{DateTime.UtcNow}: {Message}");
}
public Log(Exception ex){
Log(ex.Message);
}
}
This class doesn't know how to write a file, or console, or post the message to a web service, or email it, or put it in a rabbit queue etc.. all it knows how to do is formulate a log message provided into having a time at the start, or pull the message out of an exception(and then pass it to the method that puts a time at the start), and then call the Action (a neater way of declaring a delegate that takes arguments of various types and returns no value) passing in the message
The Action is some variable(able to be varied) method created by you
We might use it like this:
public class Program
{
public static void Main()
{
//it's a "local function", IMHO a neater way of providing a method that can be passed as an action
void consoleWriterFunc(string f){
Console.WriteLine(f);
};
//see the thing we pass as the Action parameter is a method/function,
//not a data item like a string, int, Person etc
var logger = new FlexibleLogger(consoleWriterFunc);
//log will make a string like "12-Dec-2020 12:34:56: a"
//and invoke the consoleWriterFunc, passing the string into it
//in turn it prints to the console
logger.Log("a");
//how about a logger that writes a file?
void fileWriterFunc(string f){
File.AppendAllText("c:\\temp\\some.log", f);
};
logger = new FlexibleLogger(fileWriterFunc);
logger.Log(new Exception("something bad happened"));
}
}
Doesn't have to be a local function, you can pass any method at all that takes a string and returns a void, as your Action<string>. It doesn't even have to be a method you wrote:
var sw = new System.IO.StringWriter();
var logger = new FlexibleLogger(sw.Write);
logger.Log("I'm now in the string writer" );
Microsoft wrote the method StringWriter.Write- it takes a strong, returns a void and calling logger.Log having passed the Write method of that stribgwriter instance means that the logger will Log into the stringwriter (a wrapper around a stringbuilder)
Hopefully this helps you understand that a delegate is "just a way to make a method into something you can pass as a parameter, just like anything else. They've been available for years, if you think about it, manifested as events. Microsoft have no idea what you want to do when you click a button, so they just have the button expose an event, which is really just a collection of delegates; a List of methods that the button should call when it's clicked.
Greeting fellow programmers!
I am currently studying software development (I started not a month ago) and I have a problem that needs a solution. Underneath you can find the code and as you can see, the method WriteNumber needs help. I need to write the code in a way that when I run the program, on the console screen the following two lines will be shown:
Hello World!
81
The Main method code cannot be changed and also I cannot add more methods to the class Calculator so the code needs to be done only within the WriteNumbers method. I have tried a lot of things but I am still grasping how everything works so any help is welcome! Thank you in advance for your time.
Namespace CalculatorTest
{
class Calculator
{
public static string WriteText (string input)
{
return "" + input;
}
public static string WriteNumber()
{
}
}
class Program
{
static void Main(string[] args)
{
string s = Calculator.WriteText("Hello World!");
Console.WriteLine(s);
string n = Calculator.WriteNumber(53 + 28);
Console.WriteLine(n);
Console.Read();
}
}
Not to do your homework for you to just be copied/pasted, hopefully I can give you some hints...
Notice how the method is being invoked:
Calculator.WriteNumber(53 + 28)
The 53 + 28 part happens first, then the result of that operation is passed to the method. That result, naturally, is 81. What's important about that is its type, which is an integer.
So, reasonably, the method signature needs to accept an int as a parameter. This would be done very similarly to how the other method accepts a string as a parameter:
public static string WriteText(string input)
What, then, does that method need to do with that input? Well, it's only a single value, so there aren't any calculations to be performed on it. It would appear that the method simply needs to return the value as a string. (It's your homework so you tell me, is that correct?)
This can be done with exactly two things:
Calling .ToString() on the value
Using the return keyword to return the result of that operation
(Note: The .ToString() operation does something very intuitive on value types, such as int or double or bool. As you progress into using reference types, you're going to find that it does something very different. Any time you have a custom class on which you want to call .ToString(), you'll need to override the .ToString() method on that class first.)
Please read David's answer, it's important that you make the effort to understand why this works the way it does. That being said:
public static string WriteNumber(int number)
{
return number.ToString();
}
Thank you all for your valuable input but special thanks to David because he showed where I made my error. I forgot that the two numbers in the main function will be summed up FIRST and THEN forwarded to the method in the class Calculator. After that got cleared up, it was easy to understand what to do (basically adjust the type of the input parameter to int).
namespace CalculatorTest
{
class Calculator
{
public static string WriteText (string input)
{
return "" + input;
}
public static string WriteNumber(int sumOfNumbers)
{
return "" + sumOfNumbers;
}
}
class Program
{
static void Main(string[] args)
{
string s = Calculator.WriteText("Hello World!");
Console.WriteLine(s);
string n = Calculator.WriteNumber(53 + 28);
Console.WriteLine(n);
Console.Read();
}
}
}
private void Method1()
{
//Do something
Log("Something","Method1");
}
private void Method2()
{
//Do something
Log("Something","Method2");
}
private void Log(string message, string method)
{
//Write to a log file
Trace.TraceInformation(message + "happened at " + method);
}
I have several methods like Method1 and Method2 above, and i would like some way pass the method's name as a parameter, without manually editing the code.
Is that possible?
As of C# 5, this is really easy using caller info attributes:
private void Method1()
{
//Do something
Log("Something");
}
private void Method2()
{
//Do something
Log("Something");
}
private void Log(string message, [CallerMemberName] string method = null)
{
//Write to a log file
Trace.TraceInformation(message + "happened at " + method);
}
In terms of getting this working:
You must be using the C# 5 (or later) compiler, otherwise it won't know to handle the attributes specially
The attributes have to exist in your target environment. Options there:
In .NET 4.5 the attributes are simply present
For .NET 4 you can use the Microsoft.Bcl NuGet package
For earlier versions of .NET, copy the attribute declaration into your own code, making sure you use the same namespace. When you later move to a new version of .NET, you'll need to remove it again.
Excellent answer from Jon Skeet.
However, if you don't use .NET 4.5 , you can try reflection. How ever you should know that reflection must be used only when it is absolutely necessary. Do not over-use it for the sake of using it.
Coming back,
You could do something like,
using System.Reflection; //include Reflection namespace
Console.WriteLine(MethodBase.GetCurrentMethod().Name) //Get the method-name of the current method
In your case, it would be like below,
private void Method1()
{
//Do something
Log("Something", System.Reflection.MethodBase.GetCurrentMethod().Name);
}
private void Method2()
{
//Do something
Log("Something", System.Reflection.MethodBase.GetCurrentMethod().Name);
}
private void Log(string message, string method)
{
//Write to a log file
Trace.TraceInformation(message + "happened at " + method);
}
EDIT:
As per the below comments from #Jon Skeet's, if you want .Net 4.5 kind of fancy and neat implementation, check out the Micrsoft.Bcl NUGET Package.
Aspect Oriented Programming (AOP) usually allows to achieve such tasks. You can have a look at the free version of PostSharp, especially the Logging aspect is helpful in your case.
Your code then looks like this:
[LogAspect("Something")]
void Method1(string name)
{
}
You can use PostSharp down to .NET framework 2.0.
I have created a Hello World program and I am new to C#, My program will print 100 words like that as follow
public static void Main(/*I forgot arguments*/)
{
string []s=new string [100];
foreach(string ss in s)
{
ss="Hello World";
Console.WriteLine("{0}\n",ss);
}
}
Could you show me step-by-step how to create a test for this program ? Does it need one ? I don't have an image of how testers do the test. Sorry I am stupid.
I think I have tried my best, no one ever find I find it unworthy to me not to get any help ? I don't need the class because I forgot the class long ago after the accident.
First of all, you can't (or - you shouldn't) test void methods. You are testing the output of the method - which Main does not have. Second thought: you cannot mock (simulate) an Console object. Read some tutorials about mock and mocking.
Sample method with sample test could look similar to this:
public class SimpleCalculator
{
public int SumTwoNumbers(int number1, int number2)
{
return number1 + number2;
}
}
[TestClass]
public class TestClass
{
[TestMethod]
public void Test_SimpleCalculator_SumTwoNumbers_CorrectValues()
{
// Arrange
SimpleCalculator calc = new SimpleCalculator();
// Act
int result = calc.SumTwoNumbers(5, 2);
// Assert
Assert.AreEqual(7, result);
}
}
Hope this helped a little.
Why would you need a test for this? What would you be testing for? Instead of how to test the code I'd be looking at how you can make it better.
Have a look at the Main below.
public static void Main(/*I forgot arguments*/)
{
for(var i = 0; i < 100; i++)
{
Console.WriteLine("Hello World");
}
}
Note, you don't use the array you create so there is no need to create it. Use a for loop when you know exactly how many times you need to loop. Also, there is no to format your string if you are not concating it with other strings.
Flush the above code to a method than having it in the main. Then refer to some unit test cases documents (If unit testing is what your looking for) here http://www.nunit.org/index.php?p=quickStart&r=2.5.10
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.