Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Generics overload

Generics overload

Scheduled Pinned Locked Moved C#
csharphelpquestion
6 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    Bernhard Hiller
    wrote on last edited by
    #1

    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 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 : 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 an IDisposable, I failed to get that in the previous StopWatch

    Richard DeemingR L 2 Replies Last reply
    0
    • B Bernhard Hiller

      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 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 : 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 an IDisposable, I failed to get that in the previous StopWatch

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      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

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      B 1 Reply Last reply
      0
      • Richard DeemingR Richard Deeming

        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

        B Offline
        B Offline
        Bernhard Hiller
        wrote on last edited by
        #3

        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!

        Richard DeemingR 1 Reply Last reply
        0
        • B Bernhard Hiller

          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!

          Richard DeemingR Offline
          Richard DeemingR Offline
          Richard Deeming
          wrote on last edited by
          #4

          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

          "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

          B 1 Reply Last reply
          0
          • B Bernhard Hiller

            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 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 : 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 an IDisposable, I failed to get that in the previous StopWatch

            L Offline
            L Offline
            Lost User
            wrote on last edited by
            #5

            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

            1 Reply Last reply
            0
            • Richard DeemingR Richard Deeming

              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

              B Offline
              B Offline
              Bernhard Hiller
              wrote on last edited by
              #6

              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!

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups