calling an overloaded method in generic method

后端 未结 5 1652
日久生厌
日久生厌 2021-01-12 23:18
class Test
{
    public BinaryWriter Content { get; private set; }
    public Test Write (T data)
    {
        Content.Write(data);
        return this;
           


        
相关标签:
5条回答
  • 2021-01-12 23:52

    This is possible but not with generic constraints . You can try to use Reflection and get the appropriate overloaded version of Write method according to type of T.

    Initialize your BinaryWriter with a Stream in your constructor then use Reflection like below:

    class Test
    {
        public BinaryWriter Content { get; private set; }
    
        public Test(Stream stream)
        {
            Content = new BinaryWriter(stream);
        }
    
        public Test Write<T>(T data)
        {
    
            var method = typeof (BinaryWriter).GetMethod("Write", new[] {data.GetType()});
            if (method != null)
            {
                method.Invoke(Content, new object[] { data });
            }
            // here you might want to throw an exception if method is not found
    
            return this;
        }
    }
    

    Here is a test program:

    Test writer;
    using (var fs = new FileStream("sample.txt", FileMode.Open))
    {
         writer = new Test(fs);
         writer = writer.Write(232323);
         writer = writer.Write(true);
         writer = writer.Write(12);
    }
    
    using (var fs = File.Open("sample.txt", FileMode.Open))
    {
        var reader = new BinaryReader(fs);
        Console.WriteLine(reader.ReadInt32());  // 232323
        Console.WriteLine(reader.ReadBoolean()); // true
        Console.WriteLine(reader.ReadByte());    // 12
    }
    
    0 讨论(0)
  • 2021-01-12 23:55
    1. Using Reflection considerably slows down method calls. It also moves argument type check from compile time to runtime, which is undesirable in most cases.

    2. Using dynamic calls in this case is just a fancy and slightly optimized version of the previous method which has the same drawbacks.

    3. The correct way is to copy all overloads:

      public Test Write (bool data)
      {
          Content.Write(data);
          return this;
      }
      
      public Test Write (byte data)
      {
          Content.Write(data);
          return this;
      }
      
      public Test Write (byte[] data)
      {
          Content.Write(data);
          return this;
      }
      
      public Test Write (char data)
      {
          Content.Write(data);
          return this;
      }
      
      public Test Write (char[] data)
      {
          Content.Write(data);
          return this;
      }
      
      // ...
      

      This method is very verbose, but it is the only that provides compile-time checks of arument types and is the most performant as it chooses overloads and compile-time. Furthermore, these methods are likely to be inlined.

      In cases like this, I usually use a T4 script which generates code like above based on Reflection. Create a TT file, enumerate Write overloads of BinaryWriter, generate code.

    0 讨论(0)
  • 2021-01-13 00:10

    In your write method T is generic, which means that T can be anything, but BinaryWriter.Write doesn't takes a generic overload. So you can't do that.

    0 讨论(0)
  • 2021-01-13 00:11

    Overload resolution happens at compile-time, and in this case nothing is known about T, so no overload is applicable.

       class Test
        {
            public BinaryWriter Content { get; private set; }
            public Test Write<T>(T data)
            {
                Content.Write((dynamic)data);
                return this;
            }
        }
    

    But of course it could make some problems. For example, appliction will compile fine, if you will send DateTime to the method. But, it will throw exception.

    0 讨论(0)
  • 2021-01-13 00:14

    You can't do that.

    Since real type of T is unknown at compile-time, compiler can't find appropriate Write overload, and tries to call the first found one. There is no overload, which could be called with any type of T (e.g., Write(object)).

    0 讨论(0)
提交回复
热议问题