|
I try to create a wrapper for measuring the execution time.
With actions its simple:
public static class StopWatch
{
public static TimeSpan MeasureAction(Action _action)
{
Stopwatch watch = Stopwatch.StartNew();
_action();
watch.Stop();
return watch.Elapsed;
}
}
Also, common return types are not a problem, I added an extra class for returning the duration plus the "normal" result (.Net 4.5, so the more modern Tuples whose contents have names beyond Item1 etc are not available):
internal class MeasuredExecution<T> : IMeasuredExecution<T>
{
public MeasuredExecution(TimeSpan _duration, T _result)
{
Duration = _duration;
Result = _result;
}
public TimeSpan Duration { get; }
public T Result { get; }
}
public static class StopWatch<T>
{
public static IMeasuredExecution<T> MeasureFunction(Func<T> _function)
{
Stopwatch watch = Stopwatch.StartNew();
T result = _function();
watch.Stop();
return new MeasuredExecution<T>(watch.Elapsed, result);
}
}
Now comes the problem I am looking for a better solution: the return value may be an IDisposable . In order to properly use it with a using clause, I need a wrapper exposing the IDisposable interface and calling Dispose on the Result . That wrapper part is easy, but what about the StopWatch ? I created another class:
internal class DisposableMeasuredExecution<T> : MeasuredExecution<T>, IDisposableMeasuredExecution<T> where T : IDisposable
{
public DisposableMeasuredExecution(TimeSpan _duration, T _result)
: base(_duration, _result) { }
public void Dispose()
{
Result.Dispose();
}
}
public static class StopWatchD<T> where T : IDisposable
{
public static IDisposableMeasuredExecution<T> MeasureFunction(Func<T> _function)
{
Stopwatch watch = Stopwatch.StartNew();
T result = _function();
watch.Stop();
return new DisposableMeasuredExecution<T>(watch.Elapsed, result);
}
}
Due to the extra constraint that T must now be an IDisposable , I failed to get that in the previous StopWatch class, even when using a different function name.
That feels like a WTF. Do you have any ideas how to accomplish that?
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
You can't overload a function based on the generic type constraints. And you can't add type constraints to a class-level type parameter just for one method.
What you can do is add the type parameter to the method instead of the class, and use a different function name.
public static class StopWatch
{
public static TimeSpan MeasureAction(Action _action)
{
Stopwatch watch = Stopwatch.StartNew();
_action();
watch.Stop();
return watch.Elapsed;
}
public static IMeasuredExecution<T> MeasureFunction<T>(Func<T> _function)
{
Stopwatch watch = Stopwatch.StartNew();
T result = _function();
watch.Stop();
return new MeasuredExecution<T>(watch.Elapsed, result);
}
public static IDisposableMeasuredExecution<T> MeasureFunctionDisposable<T>(Func<T> _function) where T : IDisposable
{
Stopwatch watch = Stopwatch.StartNew();
T result = _function();
watch.Stop();
return new DisposableMeasuredExecution<T>(watch.Elapsed, result);
}
} Alternatively, you could make IMeasuredExecution<T> implement IDisposable so that you wouldn't need a separate method:
public interface IMeasuredExecution<T> : IDisposable
{
TimeSpan Duration { get; }
T Result { get; }
}
internal class MeasuredExecution<T> : IMeasuredExecution<T>
{
public MeasuredExecution(TimeSpan _duration, T _result)
{
Duration = _duration;
Result = _result;
}
public TimeSpan Duration { get; }
public T Result { get; }
public void Dispose()
{
var value = Result as IDisposable;
if (value != null) value.Dispose();
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: add the type parameter to the method instead of the class, and use a different function name That's where I failed orginally. But, after changing T to T1 - thus using a different name for the type parameter - it works.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
It'll be easier to call if you only put the type parameter on the method.
StopWatch.MeasureFunction(() => 42);
StopWatch.MeasureFunctionDisposable(CreateSomeDisposableThing);
StopWatch<int>.MeasureFunction(() => 42);
StopWatch<object>.MeasureFunctionDisposable(CreateSomeDisposableThing);
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Those generic type parameters are still a cause of confusion for me...
Thanks for the hint, that's far easier, and the places where the methods are used are far better to read.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
If you "logged" from your stopwatch class, you wouldn't have to worry (so much) about the return values; seems the "api" would be simpler too.
The custom measurement calls could stay in permanently; activated or filtering at will.
You can go up the stack and tell who called who.
The Master said, 'Am I indeed possessed of knowledge? I am not knowing. But if a mean person, who appears quite empty-like, ask anything of me, I set it forth from one end to the other, and exhaust it.'
― Confucian Analects
|
|
|
|
|
Hi all,
- I am very new to c# so please be easy on me -
I have this following code which works perfectly fine:
string directory = Path.Combine(assemblyDirectory, "lib", "NetworkConnections");
using (AssemblyCatalog assemblyCatalog = new AssemblyCatalog(typeof(NetworkConnectionsManager).Assembly))
using (DirectoryCatalog directoryCatalog = new DirectoryCatalog(directory))
using (AggregateCatalog aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog))
{
compositionContainer = new CompositionContainer(aggregateCatalog);
networkConnectionsManager = compositionContainer.GetExportedValue<NetworkConnectionsManager>();
}
networkConnectionsToUpstreamProxySettingsMap = networkConnectionsManager
.GetAllConnectionFullNames()
.ToDictionary(cn => cn, cn => networkConnectionsManager.GetCurrentProxySettingsForConnection(cn));
}
(There are dll's located in ./lib/NetworkConnections)
Now I want to embed everything into a single exe. I used Fody Costura, which worked as expected as produced a single exe, but when I run my code I got an exception about lib/NetworkConnections/Telerik.NetworkConnections.dll file not found.
I tried changing the line to this instead:
string directory = "/";
Which now gives a different exception:
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
on this line:
.ToDictionary(cn => cn, cn => networkConnectionsManager.GetCurrentProxySettingsForConnection(cn));
is anyone able to help me as to what I am doing wrong? thank you so much in advance!
|
|
|
|
|
adding double quote around variable add one backslash which causing issue at sql server level. see the below code where i am adding double quote around variable and when i am printing string variable value then i am seeing many extra back slash has been added to string variable. when i am sending that data to xml causing issue.
string abc = "<Broker Code=" + '"' + strbrokercode + '"' + " IsAllowEstimate=" + '"' + IsAllowEstimate + '"' + " ReviseDate=" + '"' + ReviseDate + '"' + " BrokerEarnings=" + '"' + BrokerEarnings + '"' + " BrokerName=" + '"' + BrokerName + '"' + "></Broker>";
i tried to replace back slash with empty string but that did not work. please give me some solution.
|
|
|
|
|
Two ways:
1) The standard way - escape it with a backslash:
string abc = "<Broker Code=\"" + strbrokercode + "\" IsAllowEstimate=\"" + IsAllowEstimate + "\" ReviseDate=\"" + ReviseDate + "\" BrokerEarnings=\"" + BrokerEarnings + "\" BrokerName=\""+ BrokerName + "\"></Broker>";
2) Disable the escape character and use two double quotes together:
string abc = @"<Broker Code=""" + strbrokercode + """ IsAllowEstimate=""" + IsAllowEstimate + """ ReviseDate=""" + ReviseDate + """ BrokerEarnings=""" + BrokerEarnings + """ BrokerName="""+ BrokerName + """></Broker>"; But a more readable way would be to use string interpolation if your compiler supports it:
string abc = $"<Broker Code=\"{strbrokercode}\" IsAllowEstimate=\"{IsAllowEstimate}\" ReviseDate=\"{ReviseDate}\" BrokerEarnings=\"{BrokerEarnings}\" BrokerName=\"{BrokerName}\"></Broker>";
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I test below code which did not compile
string abc = @"<Broker Code=""" + strbrokercode + """ IsAllowEstimate=""" + IsAllowEstimate + """ ReviseDate=""" + ReviseDate + """ BrokerEarnings=""" + BrokerEarnings + """ BrokerName="""+ BrokerName + """></Broker>";
please compile it.
|
|
|
|
|
If you're generating XML, then it would be better to actually generate XML. There are many "special" characters which need to be encoded for use in XML.
string abc = new System.Xml.Linq.XElement("Broker",
new System.Xml.Linq.XAttribute("Code", strbrokercode),
new System.Xml.Linq.XAttribute("IsAllowEstimate", IsAllowEstimate),
new System.Xml.Linq.XAttribute("ReviseDate", ReviseDate),
new System.Xml.Linq.XAttribute("BrokerEarnings", BrokerEarnings),
new System.Xml.Linq.XAttribute("BrokerName", BrokerName)
).ToString();
Mou_kol wrote: i am seeing many extra back slash has been added to string variable
It's more likely that you're seeing the debugger output, which shows you how the string would be declared in C#. It doesn't actually add the backslash characters to the string.
If you click on the "magnifying glass" button to the left of the string value in the data tip[^], you'll be able to view the actual string value.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks a lot for your answer.
see this code
string strbrokercode="ML";
string IsAllowEstimate="true";
string ReviseDate="true";
string BrokerEarnings="true";
string BrokerName="true";
StringBuilder sb = new StringBuilder();
string abc = "<Broker Code=" + '"' + strbrokercode + '"' + " IsAllowEstimate=" + '"' + IsAllowEstimate + '"' + " ReviseDate=" + '"' + ReviseDate + '"' + " BrokerEarnings=" + '"' + BrokerEarnings + '"' + " BrokerName=" + '"' + BrokerName + '"' + "></Broker>";
sb.Append(abc);
when i type sb.ToString() in immediate window then output print like below one which causing problem for me.
"<Broker Code=\"ML\" IsAllowEstimate=\"true\" ReviseDate=\"true\" BrokerEarnings=\"true\" BrokerName=\"true\"></Broker>"
Please share your suggestion. thanks
|
|
|
|
|
As I said, those backslashes do not exist in your string. The "immediate" window is encoding the string to match what you would have to type to declare it in your C# code.
Use the debugger visualizer instead.
Newlines in the immediate window – jaredpar's WebLog[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
thanks
|
|
|
|
|
I understand the answer is "yes" as compared to just instantiating objects and never disposing, clearing, or closing them.
But those two are not the only alternatives.
"using" get compiled as try-finally anyway. (See using statement - C# Reference | Microsoft Docs[^] )
However, if you use try-catch-finally, you achieve the same results (calling Dispose in the finally block), but can gain benefits.
1 - Capture of runtime data for troubleshooting. If you specify the catch block, you can add name-value pairs for runtime values to the Exception.Data collection. Logging can then pull these values out when the exception is logged, wherever you choose on the stack.
2 - When troubleshooting in the IDE, you can step through the "cleanup" in catch and finally, which you cannot do with the "using" statement. This reduces initial development time and troubleshooting time.
3 - You have full control over the order and operations of releasing resources. Not all objects inherit IDisposable. In addition, a given object may have child objects or other objects in a collection that need to be separately disposed of (think .Clear()). Using the finally block, you have control over how objects are cleaned up, and if any logging is needed.
The downside is that using try-catch-finally takes a little more coding time upfront. However, most of that should be copy-and-paste. Doing so will, in the aggregate, also save you a little time, so it should balance out, leaving you with better, less buggy, code.
IMHO, if I create an object, I should clean it up and not leave that to chance or the hope that under the covers, MS got the "using" statement right.
That said, what are your views on using the "using" statement?
|
|
|
|
|
Consider multiple using blocks - would you really prefer the try..finally version?
using (SqlConnection connection = new SqlConnection("..."))
using (SqlCommand command = new SqlCommand("...", connection))
{
...
using (SqlDataReader reader = command.ExecuteReader())
{
...
}
} vs:
{
SqlConnection connection = new SqlConnection("...");
try
{
{
SqlCommand command = new SqlCommand("...", connection);
try
{
...
{
SqlDataReader reader = command.ExecuteReader();
try
{
...
}
finally
{
if (reader != null)
((IDisposable)reader).Dispose();
}
}
}
finally
{
if (command != null)
((IDisposable)command).Dispose();
}
}
}
finally
{
if (connection != null)
((IDisposable)connection).Dispose();
}
}
MSBassSinger wrote: 1 - Capture of runtime data for troubleshooting.
There's nothing stopping you from putting a try..catch block either inside or outside of your using block. You can still add any extra data to the exception as required.
MSBassSinger wrote: 3 - You have full control over the order and operations of releasing resources.
Disposable objects should be responsible for cleaning up their own resources. It shouldn't be up to the caller to know that they need to clean up a child collection before calling Dispose .
MSBassSinger wrote: the hope that under the covers, MS got the "using" statement right.
It's been around for almost two decades. If they hadn't got it right, then you'd have heard about it by now.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Yes, even more so I would avoid the using statement. However, your alternative code is nothing like what I would write. No need for the nested try-finally blocks.
Quote: There's nothing stopping you from putting a try..catch block either inside or outside of your using block. You can still add any extra data to the exception as required.
Then why bother with the using statements? They are redundant.
Quote: Disposable objects should be responsible for cleaning up their own resources. It shouldn't be up to the caller to know that they need to clean up a child collection before calling Dispose.
As I said, not all objects that utilize resources inherit IDisposable. They *should*, and when they do, they *should* completely clean up their resources. By having a consistent practice of not using the using statement and coding the try-catch-finally blocks, I have better step-through debugging and better control over cleaning up my resources for when those edge case situations occur.
I am not saying it is "wrong" to use the using statement. I am merely saying why, after years of experience, I choose not to use it.
I appreciate that you responded, and it does go to the point of understanding why others do choose to use the using statement.
|
|
|
|
|
MSBassSinger wrote: No need for the nested try-finally blocks.
Without them, you can easily introduce bugs where resources don't get cleaned up.
For example:
SqlConnection connection = new SqlConnection("...");
SqlCommand command = new SqlCommand("...", connection);
try
{
...
}
finally
{
if (command != null) ((IDisposable)command).Dispose();
if (connection != null) ((IDisposable)connection).Dispose();
} If the SqlCommand ctor throws an exception, the SqlConnection is never cleaned up.
To do it properly, you would need something like:
SqlConnection connection = null;
SqlCommand command = null;
try
{
connection = new SqlConnection("...");
command = new SqlCommand("...", connection);
...
}
finally
{
if (command != null) ((IDisposable)command).Dispose();
if (connection != null) ((IDisposable)connection).Dispose();
} It's quite a lot of boilerplate and ceremony that the developer needs to get just right to make it work as well as a couple of using blocks.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Quote: Without them, you can easily introduce bugs where resources don't get cleaned up.
Example #1 is something only a novice would do, and novices have manifold ways of introducing bugs. Your 2nd example is exactly what I do - no bugs introduced. And in that example, it only adds two lines of code.
So yes, I much prefer the 2nd example over the using statement(s) for the flexibility I described in the OP. And it doesn't slow me down. After all, coding is only a fraction of the time wed spend doing software development.
|
|
|
|
|
As with every other tool in the box, you must know what it's doing in the background for you, since it is just syntactic sugar, and how to use it properly.
A using block should be used where appropriate. If you don't care about your items 1, 2, and 3 for a certain block of code, then a using block is just fine.
|
|
|
|
|
Quote: A using block should be used where appropriate
Where would you consider appropriate?
Thanks for taking time to respond.
|
|
|
|
|
Again, If you don't care about your items 1, 2, and 3 for a certain block of code, then a using block is just fine.
If I build a SqlConnection and SqlCommand, do I really care about your list of items? Nope. I'm going to concerned with just two things. Any exceptions thrown by the Command and the data returned. That's scoped to the inside of the using block. The method this block is in is either going to let the exception bubble up or it's going to return data. Nothing more.
|
|
|
|
|
Quote: I'm going to concerned with just two things. Any exceptions thrown by the Command and the data returned.
I understand and agree with what you say. But, I look for more. When something does go wrong in production, I'd like the debug log to have captured the runtime values of what I was using in the SqlConnection and SqlCommand object. With those, I can quickly tell if there was something wrong with the values (e.g. did someone diddle with a config file that had connection info?). Or maybe some of my query parameter values were unexpected. In any case, by having captured them in a catch block, I spend 5 minutes on solving a problem, instead of an hour or more guessing at what might have caused it. I could embed a try-catch within the using statement (not sure if the instantiation portion of the using statement would get "caught" in the catch block, though), but then if I have the try-catch, why not just add finally and do away with the redundancy of the using statement?
If the values seem OK, with the try-catch-finally, I can step through all the code, which is limited with the using statement.
I understand if these things are not valuable to you. But they are to me after many years of running into the odd issues that could have been solved by a couple more lines of code. Every developer has to pick and chose what they consider valuable to them, as well as to a customer.
|
|
|
|
|
Again, if you want that flexibility, don't us a using .
I don't have a need for the "what if" situation you posted, so I could easily just go with a using and not worry about it crashing under circumstances that were unexpected.
If I need to consider that the values are critical and need to be checked out in the future, I can always wrap it some logging code, or implement the using my self.
You're answering your own question.
|
|
|
|
|
I have to agree with Richard - using is cleaner, clearer, and easier to use.
And ... it makes the scope of the variable very, very obvious which a try...finally block doesn't - when you use the try...finally version, the scope of the variable is the block which contains the try...finally code (or it wouldn't be available for Dispose in the finally block) so you could write code to use a variable after it's content is Disposed:
SqlCommand cmd = new SqlCommand(sql, con);
try
{
...
}
finally
{
if (cmd != null) cmd.Dispose();
}
cmd.ExecuteNonQuery();
using (SqlCommand cmd = new SqlCommand(sql, con))
{
...
}
cmd.ExecuteNonQuery();
Sent from my Amstrad PC 1640
Never throw anything away, Griff
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|