Generics overload
-
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 : IMeasuredExecution { public MeasuredExecution(TimeSpan \_duration, T \_result) { Duration = \_duration; Result = \_result; } public TimeSpan Duration { get; } public T Result { get; } } public static class StopWatch { public static IMeasuredExecution MeasureFunction(Func \_function) { Stopwatch watch = Stopwatch.StartNew(); T result = \_function(); watch.Stop(); return new MeasuredExecution(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 ausing
clause, I need a wrapper exposing theIDisposable
interface and callingDispose
on theResult
. That wrapper part is easy, but what about theStopWatch
? I created another class:internal class DisposableMeasuredExecution : MeasuredExecution, IDisposableMeasuredExecution where T : IDisposable { public DisposableMeasuredExecution(TimeSpan \_duration, T \_result) : base(\_duration, \_result) { } public void Dispose() { Result.Dispose(); } } public static class StopWatchD where T : IDisposable { public static IDisposableMeasuredExecution MeasureFunction(Func \_function) { Stopwatch watch = Stopwatch.StartNew(); T result = \_function(); watch.Stop(); return new DisposableMeasuredExecution(watch.Elapsed, result); } }
Due to the extra constraint that
T
must now be anIDisposable
, I failed to get that in the previousStopWatch
-
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 : IMeasuredExecution { public MeasuredExecution(TimeSpan \_duration, T \_result) { Duration = \_duration; Result = \_result; } public TimeSpan Duration { get; } public T Result { get; } } public static class StopWatch { public static IMeasuredExecution MeasureFunction(Func \_function) { Stopwatch watch = Stopwatch.StartNew(); T result = \_function(); watch.Stop(); return new MeasuredExecution(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 ausing
clause, I need a wrapper exposing theIDisposable
interface and callingDispose
on theResult
. That wrapper part is easy, but what about theStopWatch
? I created another class:internal class DisposableMeasuredExecution : MeasuredExecution, IDisposableMeasuredExecution where T : IDisposable { public DisposableMeasuredExecution(TimeSpan \_duration, T \_result) : base(\_duration, \_result) { } public void Dispose() { Result.Dispose(); } } public static class StopWatchD where T : IDisposable { public static IDisposableMeasuredExecution MeasureFunction(Func \_function) { Stopwatch watch = Stopwatch.StartNew(); T result = \_function(); watch.Stop(); return new DisposableMeasuredExecution(watch.Elapsed, result); } }
Due to the extra constraint that
T
must now be anIDisposable
, I failed to get that in the previousStopWatch
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>
implementIDisposable
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
-
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>
implementIDisposable
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
toT1
- thus using a different name for the type parameter - it works.Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
-
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
toT1
- 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. :)
// Type parameter on the method - the compiler infers the type:
StopWatch.MeasureFunction(() => 42);
StopWatch.MeasureFunctionDisposable(CreateSomeDisposableThing);// Type parameter on the class - you must specify the type:
StopWatch<int>.MeasureFunction(() => 42);// Type parameter on the class and the method - you must specify the type for the class, but it's not used by the method:
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
-
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 : IMeasuredExecution { public MeasuredExecution(TimeSpan \_duration, T \_result) { Duration = \_duration; Result = \_result; } public TimeSpan Duration { get; } public T Result { get; } } public static class StopWatch { public static IMeasuredExecution MeasureFunction(Func \_function) { Stopwatch watch = Stopwatch.StartNew(); T result = \_function(); watch.Stop(); return new MeasuredExecution(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 ausing
clause, I need a wrapper exposing theIDisposable
interface and callingDispose
on theResult
. That wrapper part is easy, but what about theStopWatch
? I created another class:internal class DisposableMeasuredExecution : MeasuredExecution, IDisposableMeasuredExecution where T : IDisposable { public DisposableMeasuredExecution(TimeSpan \_duration, T \_result) : base(\_duration, \_result) { } public void Dispose() { Result.Dispose(); } } public static class StopWatchD where T : IDisposable { public static IDisposableMeasuredExecution MeasureFunction(Func \_function) { Stopwatch watch = Stopwatch.StartNew(); T result = \_function(); watch.Stop(); return new DisposableMeasuredExecution(watch.Elapsed, result); } }
Due to the extra constraint that
T
must now be anIDisposable
, I failed to get that in the previousStopWatch
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
-
It'll be easier to call if you only put the type parameter on the method. :)
// Type parameter on the method - the compiler infers the type:
StopWatch.MeasureFunction(() => 42);
StopWatch.MeasureFunctionDisposable(CreateSomeDisposableThing);// Type parameter on the class - you must specify the type:
StopWatch<int>.MeasureFunction(() => 42);// Type parameter on the class and the method - you must specify the type for the class, but it's not used by the method:
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!