C#的泛型方法解析

2019-12-30 15:03:36刘景俊

   备注:类型推断只适用于泛型方法,不适用于泛型类型。

  以上是对泛型方法的相关概念和约束做了简单的解析,接下来看一下.NET中一些发行方法的具体实现:


 /// <summary>
 /// 封装一个方法,该方法具有四个参数并且不返回值。
 /// </summary>
 /// <param name="arg1">此委托封装的方法的第一个参数。</param><param name="arg2">此委托封装的方法的第二个参数。</param><param name="arg3">此委托封装的方法的第三个参数。</param><param name="arg4">此委托封装的方法的第四个参数。</param><typeparam name="T1">此委托封装的方法的第一个参数类型。</typeparam><typeparam name="T2">此委托封装的方法的第二个参数类型。</typeparam><typeparam name="T3">此委托封装的方法的第三个参数类型。</typeparam><typeparam name="T4">此委托封装的方法的第四个参数类型。</typeparam><filterpriority>2</filterpriority>
 [TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")]
 [__DynamicallyInvokable]
 public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

 /// <summary>
 /// 表示比较同一类型的两个对象的方法。
 /// </summary>
 /// 
 /// <returns>
 /// 一个有符号整数,指示 <paramref name="x"/> 与 <paramref name="y"/> 的相对值,如下表所示。 值 含义 小于 0 <paramref name="x"/> 小于 <paramref name="y"/>。 0 <paramref name="x"/> 等于 <paramref name="y"/>。 大于 0 <paramref name="x"/> 大于 <paramref name="y"/>。
 /// </returns>
 /// <param name="x">要比较的第一个对象。</param><param name="y">要比较的第二个对象。</param><typeparam name="T">要比较的对象的类型。</typeparam><filterpriority>1</filterpriority>
 [__DynamicallyInvokable]
 public delegate int Comparison<in T>(T x, T y);

  四.泛型方法应用代码示例:

   以上讲解的有关泛型方法的内容,这里提供一个有关泛型方法操作XML的代码:


 /// <summary>
 /// 泛型方法:编译器能够根据传入的方法参数推断类型参数;它无法仅从约束或返回值推断类型参数
 /// </summary>
 public class ObjectXmlSerializer
 {
  /// <summary>
  /// 文件的反序列化
  /// </summary>
  /// <typeparam name="T">返回值类型</typeparam>
  /// <param name="fileName"></param>
  /// <returns>
  /// 如果日志启用,则发生异常时,异常写入日志,若日志没有开启,则直接抛出异常信息
  /// loggingEnabled==true: Null is returned if any error occurs.
  /// loggingEnabled==false: throw exception
  /// </returns>
  public static T LoadFromXml<T>(string fileName) where T : class
  {
   return LoadFromXml<T>(fileName, true);
  }
  /// <summary>
  /// 文件反序列化,若发生异常,异常信息写入日志
  /// </summary>
  /// <typeparam name="T">加载类的类型</typeparam>
  /// <param name="fileName">文件名字</param>
  /// <param name="loggingEnabled">启用日志记录</param>
  /// <returns></returns>
  public static T LoadFromXml<T>(string fileName, bool loggingEnabled) where T : class
  {
   FileStream fs = null;
   try
   {
    var serializer = new XmlSerializer(typeof(T));
    fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
    //反序列化对象
    return (T)serializer.Deserialize(fs);
   }
   catch (Exception e)
   {
    if (loggingEnabled)
    {
     //文件异常,写入日志
     LogLoadFileException(fileName, e);
     return null;
    }
    else
    {
     throw new Exception(e.Message);
    }
   }
   finally
   {
    if (fs != null) fs.Close();
   }
  }
  /// <summary>
  /// 序列化一个对象到文件中.
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="fileName">文件名</param>
  /// <param name="data">待序列化的数据</param>
  /// <returns>
  /// 如果日志启用,则发生异常时,异常写入日志,若日志没有开启,则直接抛出异常信息
  /// loggingEnabled==true: log exception
  /// loggingEnabled==false: throw exception
  /// </returns>
  public static void SaveToXml<T>(string fileName, T data) where T : class
  {
   SaveToXml(fileName, data, true);
  }
  /// <summary>
  /// 文件反序列化,若发生异常,异常信息写入日志
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="fileName">文件名</param>
  /// <param name="data">发序列化对象</param>
  /// <param name="loggingEnabled">是否启用日志</param>
  public static void SaveToXml<T>(string fileName, T data, bool loggingEnabled) where T : class
  {
   FileStream fs = null;
   try
   {
    var serializer = new XmlSerializer(typeof(T));
    fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
    //序列化对象
    serializer.Serialize(fs, data);
   }
   catch (Exception e)
   {
    if (loggingEnabled) LogSaveFileException(fileName, e);
    else
    {
     throw new Exception(e.Message);
    }
   }
   finally
   {
    if (fs != null) fs.Close();
   }
  }
  /// <summary>
  /// 序列化
  /// XML & Datacontract Serialize & Deserialize Helper
  /// </summary>
  /// <typeparam name="T">T指定必须为class类型</typeparam>
  /// <param name="serialObject"></param>
  /// <returns></returns>
  public static string XmlSerializer<T>(T serialObject) where T : class
  {
   var ser = new XmlSerializer(typeof(T));
   //MemoryStream实现对内存的读写,而不是对持久性存储器进行读写
   //MemoryStream封装以无符号字节数组形式存储的数据,该数组在创建MemoryStream对象时被初始化,
   //或者该数组可创建为空数组。可在内存中直接访问这些封装的数据。
   //内存流可降低应用程序中对临时缓冲区和临时文件的需要。
   var mem = new MemoryStream();
   var writer = new XmlTextWriter(mem, UTF8);
   ser.Serialize(writer, serialObject);
   writer.Close();
   return UTF8.GetString(mem.ToArray());
  }
  /// <summary>
  /// 反序列化
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="str"></param>
  /// <returns></returns>
  public static T XmlDeserialize<T>(string str) where T : class
  {
   var mySerializer = new XmlSerializer(typeof(T));
   var mem2 = new StreamReader(new MemoryStream(UTF8.GetBytes(str)), UTF8);
   return (T)mySerializer.Deserialize(mem2);
  }
  /// <summary>
  /// 
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="xmlData"></param>
  /// <returns>返回值类型为传入的类型</returns>
  public static T DataContractDeserializer<T>(string xmlData) where T : class
  {
   var stream = new MemoryStream(UTF8.GetBytes(xmlData));
   var reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
   var ser = new DataContractSerializer(typeof(T));
   var deserializedPerson = (T)ser.ReadObject(reader, true);
   reader.Close();
   stream.Close();
   return deserializedPerson;
  }
  /// <summary>
  /// 
  /// </summary>
  /// <typeparam name="T"></typeparam>
  /// <param name="myObject"></param>
  /// <returns></returns>
  public static string DataContractSerializer<T>(T myObject) where T : class
  {
   var stream = new MemoryStream();
   var ser = new DataContractSerializer(typeof(T));
   ser.WriteObject(stream, myObject);
   stream.Close();
   return UTF8.GetString(stream.ToArray());
  }
  /// <summary>
  /// 序列化时异常日志
  /// </summary>
  /// <param name="fileName">文件名</param>
  /// <param name="ex">异常</param>
  [Conditional("TRACE")]
  private static void LogLoadFileException(string fileName, Exception ex)
  {
   var sb = new StringBuilder();
   sb.Append("Fail to load xml file: ");
   sb.Append(fileName + Environment.NewLine);
   sb.Append(ex);
   //写入日志记录中方法
   // Logger.LogEvent(LogCategory, LogEventLoadFileException, sb.ToString());
  }
  /// <summary>
  /// 反序列化时异常日志
  /// </summary>
  /// <param name="fileName">文件名</param>
  /// <param name="ex">异常</param>
  [Conditional("TRACE")]
  private static void LogSaveFileException(string fileName, Exception ex)
  {
   var sb = new StringBuilder();
   sb.Append("Fail to save xml file: ");
   sb.Append(fileName + Environment.NewLine);
   sb.Append(ex);
  }
  /// <summary>
  /// 将xml字符串序列化为数据流(数据流编码为ASCII,UTF8)
  /// </summary>
  /// <returns>字符串转换到流</returns>
  public static MemoryStream StringXmlToStream(string strXml,Encoding encod)
  {
   MemoryStream memoryStream = null;
   try
   {
    Encoding encoding;
    if (Equals(encod, ASCII))
    {
      encoding = new ASCIIEncoding();
    }
    else
    {
      encoding = new UTF8Encoding(); 
    }
    var byteArray = encoding.GetBytes(strXml);
    memoryStream = new MemoryStream(byteArray);
    memoryStream.Seek(0, SeekOrigin.Begin);
    return memoryStream;
   }
   catch (IOException ex)
   {
    throw new IOException(ex.Message);
   }
   finally
   {
    if (memoryStream != null) memoryStream.Close();
   }
  }
 }