今天有空,把C#常用的功能总结一下,希望对您有用。(适用于.NET Framework 4.5)
1. 把类转换为字符串(序列化为XML字符串,支持xml的namespace)
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
public static string Serialize<T>(T t, string nameSpacePri, string nameSpace)
{
try
{
var myNamespaces = new XmlSerializerNamespaces();
myNamespaces.Add(nameSpacePri, nameSpace);
var xs = new XmlSerializer(t.GetType());
using (var memoryStream = new MemoryStream())
{
var settings = new XmlWriterSettings()
{
Encoding = Encoding.UTF8
};
using (var writer = XmlWriter.Create(memoryStream, settings))
{
xs.Serialize(writer, t, myNamespaces);
}
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
}
catch (System.Exception)
{
return null;
}
}
2. 把带namespace的XML字符串反序列化为类对象
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
public sealed class XmlSerilizer
{
public static T Deserialize<T>(string input)
{
try
{
var xs = new XmlSerializer(typeof (T));
using (var reader = new StringReader(input))
{
var namespaceReader = new NamespaceIgnorantXmlTextReader(reader);
return (T) xs.Deserialize(namespaceReader);
}
}
catch (System.Exception e)
{
return default(T);
}
}
}
//忽略xml里面的namespace
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
/// <summary>
/// Initializes a new instance of the <see cref="NamespaceIgnorantXmlTextReader"/> class.
/// </summary>
/// <param name="reader">The reader.</param>
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader) : base(reader) { }
/// <summary>
/// Gets the namespace URI (as defined in the W3C Namespace specification) of the node on which the reader is positioned.
/// </summary>
/// <value>The namespace URI.</value>
/// <returns>The namespace URI of the current node; otherwise an empty string.</returns>
public override string NamespaceURI
{
get { return ""; }
}
}
以上要注意xml的root,实体类要这样写:
[Serializable]
[XmlRoot(ElementName = "yourXmlRootName", DataType = "string", IsNullable = true)]
public class Model
{
[XmlElement(ElementName = "merchant", IsNullable = true)]
public string merchant { get; set; }
[XmlElement(ElementName = "address", IsNullable = false)]
public string address{ get; set; }
[XmlElement(ElementName = "status", IsNullable = false)]
public string status { get; set; }
}
3. 把JSON字符串反序列化为类对象
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonString);
4. 把类对象序列化为字符串
string output = Newtonsoft.Json.JsonConvert.SerializeObject(product);
5. 获取程序的App data path
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
public static string GetApplicationDataPath()
{
try
{
var asm = Assembly.GetEntryAssembly();
var attrs = asm.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
var company = (AssemblyCompanyAttribute)attrs[0];
attrs = asm.GetCustomAttributes(typeof(AssemblyTrademarkAttribute), false);
var tradeMark = (AssemblyTrademarkAttribute)attrs[0];
var pathTemp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), company.Company);
pathTemp = Path.Combine(pathTemp, tradeMark.Trademark);
pathTemp = Path.Combine(pathTemp, asm.GetName().Name);
return pathTemp;
}
catch (System.Exception)
{
return string.Empty;
}
}
6. 清空目录(扩展方法)
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
public static void Empty(this DirectoryInfo directory)
{
foreach (FileInfo file in directory.GetFiles()) file.Delete();
foreach (DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);
}
7. 计算文件的SHA1值
using System.Security.Cryptography;
public static string CalculateFileSha(byte[] buffer)
{
using (var cryptoProvider = new SHA1CryptoServiceProvider())
{
return Convert.ToBase64String(cryptoProvider.ComputeHash(buffer));
}
}
8. 写文件(另一个线程)
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
public static void WriteFileAsync(string content, string fileName, bool append)
{
if (String.IsNullOrEmpty(content)||string.IsNullOrEmpty(fileName)) return;
Task.Factory.StartNew(() =>
{
try
{
using (var writer = new StreamWriter(fileName, append, Encoding.UTF8))
{
writer.AutoFlush = true;
writer.WriteLine(content);
writer.Close();
}
}
catch (System.Exception)
{
}
});
}
9. 等待被其它进程占用的文件
public static void WaitForFile(string fullPath)
{
while (true)
{
try
{
using (var stream = new StreamReader(fullPath))
{
break;
}
}
catch
{
Thread.Sleep(100);
}
}
}
10. XmlDocument和XDocument工具类
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace myCompany
{
public sealed class XmlUtility
{
public static XDocument DocumentToXDocument(XmlDocument doc)
{
return XDocument.Load(new XmlNodeReader(doc));
}
public static XmlDocument XDocumentToXmlDocument(XDocument doc)
{
var xmlDocument = new XmlDocument();
using (var xmlReader = doc.CreateReader())
{
xmlDocument.Load(xmlReader);
}
return xmlDocument;
}
public static XDocument XElementToXDocument(XElement element)
{
return new XDocument(element);
}
public static string RemoveAllNamespaces(string xmlDocument)
{
XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(xmlDocument));
return xmlDocumentWithoutNs.ToString();
}
public static XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
var xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
foreach (var attribute in xmlDocument.Attributes())
xElement.Add(attribute);
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
public static XDocument RemoveNamespaces(XDocument xmlDocument, string namespaces)
{
return XDocument.Parse(xmlDocument.ToString().Replace(namespaces, ""));
}
}
}
11. 使用XSLT转换两个xml
using System;
using System.Xml.Linq;
using System.Xml.Xsl;
using ETMS.MCC.Logging;
using ETMS.MCC.Utility;
namespace myCompany
{
public class Converter
{
[ThreadStatic]
private static XslCompiledTransform xslTransformer;
public XDocument XsltTransform(XDocument inputDocument)
{
System.IO.Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
return Transform(Utility.Constants.Configuration.ParameterXsltFile, inputDocument);
}
public XDocument XsltTransform(string xsltFilename, XDocument inputDocument)
{
return Transform(xsltFilename, inputDocument);
}
private XDocument Transform(string xsltFilename, XDocument inputDocument)
{
try
{
if (xslTransformer == null)
{
xslTransformer = new XslCompiledTransform();
xslTransformer.Load(xsltFilename);
}
var result = new XDocument();
using (var xw = result.CreateWriter())
{
xslTransformer.Transform(XmlUtility.XDocumentToXmlDocument(inputDocument), null, xw);
xw.Close();
return result;
}
}
catch (Exception e)
{
return null;
}
}
}
}
12. 批量任务处理,限制并发数
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public static async Task BulkExecute<T>(int maxConcurrency, IEnumerable<T> items, Func<T, Task> createTask)
{
using (var sem = new SemaphoreSlim(maxConcurrency))
{
var tasks = new List<Task>();
foreach (var item in items)
{
await sem.WaitAsync();
var task = createTask(item).ContinueWith(t => sem.Release());
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
}
13. 支持超时时间和最大容量的同步队列
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
namespace myCompany
{
public abstract class AbstractProcessingQueue<T> : ConcurrentQueue<T> where T : class
{
protected int _numberLimit;
protected int _timeLimit;
protected System.Timers.Timer _timer;
protected int _onPublishExecuted;
protected ReaderWriterLockSlim _locker;
protected AbstractProcessingQueue()
{ }
protected AbstractProcessingQueue(int numberLimit, int timeLimit)
{
Init(numberLimit, timeLimit);
}
public event Action<List<T>> OnPublish = delegate { };
public virtual new void Enqueue(T item)
{
base.Enqueue(item);
if (_numberLimit > 0 && Count >= _numberLimit)
{
Logger.GlobalWrite(string.Format("Processing queue number limit: {0}", _numberLimit), LogMessageCategory.Warning);
Publish();
}
}
private void Init(int capLimit, int timeLimit)
{
_numberLimit = capLimit;
_timeLimit = timeLimit;
_locker = new ReaderWriterLockSlim();
InitTimer();
}
protected virtual void InitTimer()
{
if (_timeLimit < 0) return;
_timer = new System.Timers.Timer {AutoReset = false, Interval = _timeLimit*1000};
_timer.Elapsed += new ElapsedEventHandler((s, e) =>
{
Logger.GlobalWrite(string.Format("Processing queue time limit: {0}", _timeLimit), LogMessageCategory.Warning);
Publish();
});
_timer.Start();
}
protected virtual void Publish()
{
var task = new Task(() =>
{
var itemsToLog = new List<T>();
try
{
if (IsPublishing())
return;
StartPublishing();
T item;
while (TryDequeue(out item))
{
itemsToLog.Add(item);
}
}
catch (ThreadAbortException tex)
{
}
catch (Exception ex)
{
}
finally
{
OnPublish(itemsToLog);
CompletePublishing();
}
});
task.Start();
}
private bool IsPublishing()
{
return (Interlocked.CompareExchange(ref _onPublishExecuted, 1, 0) > 0);
}
private void StartPublishing()
{
if (_timer != null)
_timer.Stop();
}
private void CompletePublishing()
{
if (_timer != null)
_timer.Start();
Interlocked.Decrement(ref _onPublishExecuted);
}
}
}
14. 单例模式
using System;
namespace myCompany
{
public sealed class Singleton
{
static readonly Singleton Instance = new Singleton();
private Singleton() { }
public static Singleton GetInstance()
{
return Instance;
}
}
}
15. 根据httpRequest和httpHeader里面的content-type,获得请求类型
using System;
using System.Web;
public static MediaTypes GetMediaType(string contentTypeHeader)
{
if (String.IsNullOrEmpty(contentTypeHeader))
return MediaTypes.UNKNOWN;
if (contentTypeHeader.Contains("text/plain")) return MediaTypes.TEXT;
if (contentTypeHeader.Contains("application/json")) return MediaTypes.JSON;
if (contentTypeHeader.Contains("html")) return MediaTypes.HTML;
if (contentTypeHeader.Contains("application/xml")) return MediaTypes.XML;
return MediaTypes.UNKNOWN;
}
16. 解析URL的parameter,例如http://www.abc.com?a=1&b=2&c=3,获取a,b,c
using System;
using System.Web;
public static string ParseText(string bodyText, string key)
{
var myUri = new Uri("http://www.vefifone.com?" + bodyText);
return HttpUtility.ParseQueryString(myUri.Query).Get(key);
}
17. 解析xml字符串,获取其中一个字段的值
using System.Xml;
using System.Xml.Linq;
public long ParseXmlString(string messageBody)
{
try
{
var xm = new XmlDocument();
xm.LoadXml(messageBody);
using (var reader = new XmlNodeReader(xm))
{
var Id = "";
var doc = XDocument.Load(reader);
var ele = doc.Document.Element("root1").Element("elementName");
if (ele != null)
Id = ele.Value;
long id;
if (!Int64.TryParse(Id, out id))
{
return -1;
}
return id;
}
}
catch (Exception e)
{
return -1;
}
}
18. 把多个文件内容byte[]压缩为一个zip包,返回字节流byte[]
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
public byte[] ZipFiles(IEnumerable<byte[]> contents)
{
try
{
using (var compressedFileStream = new MemoryStream())
{
using (var zipStream = new ZipOutputStream(compressedFileStream))
{
zipStream.SetLevel(9);
foreach (var p in contents)
{
using (var srcStream = new MemoryStream(p))
{
var entry = new ZipEntry("newname");
zipStream.PutNextEntry(entry);
StreamUtils.Copy(srcStream, zipStream, new byte[4096]);
zipStream.CloseEntry();
}
}
zipStream.IsStreamOwner = false;
zipStream.Close();
compressedFileStream.Position = 0;
return compressedFileStream.ToArray();
}
}
}
catch (Exception e)
{
return null;
}
}
19. 反序列化JsonDeserializer, XmlJsonDeserializer, DotNetXmlJsonDeserializer
interface IsonDeserializer:
namespace myCompany
{
public interface IDeserializer
{
T Deserialize<T>(IRestResponse response);
string RootElement { get; set; }
string Namespace { get; set; }
string DateFormat { get; set; }
}
}
JsonDeserializer:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using RestSharp.Extensions;
namespace myCompany
{
public class JsonDeserializer : IDeserializer
{
public string RootElement { get; set; }
public string Namespace { get; set; }
public string DateFormat { get; set; }
public CultureInfo Culture { get; set; }
public JsonDeserializer()
{
Culture = CultureInfo.InvariantCulture;
}
public T Deserialize<T>(IRestResponse response)
{
var target = Activator.CreateInstance<T>();
if (target is IList)
{
var objType = target.GetType();
if (RootElement.HasValue())
{
var root = FindRoot(response.Content);
target = (T)BuildList(objType, root);
}
else
{
var data = SimpleJson.DeserializeObject(response.Content);
target = (T)BuildList(objType, data);
}
}
else if (target is IDictionary)
{
var root = FindRoot(response.Content);
target = (T)BuildDictionary(target.GetType(), root);
}
else
{
var root = FindRoot(response.Content);
Map(target, (IDictionary<string, object>)root);
}
return target;
}
private object FindRoot(string content)
{
var data = (IDictionary<string, object>)SimpleJson.DeserializeObject(content);
if (RootElement.HasValue() && data.ContainsKey(RootElement))
{
return data[RootElement];
}
return data;
}
private void Map(object target, IDictionary<string, object> data)
{
var objType = target.GetType();
var props = objType.GetProperties().Where(p => p.CanWrite).ToList();
foreach (var prop in props)
{
var type = prop.PropertyType;
string name = String.Empty;
var attributes = prop.GetCustomAttributes(typeof(DeserializeAsAttribute), false);
if (attributes.Length > 0)
{
var attribute = (DeserializeAsAttribute)attributes[0];
name = attribute.Name;
}
else
{
name = prop.Name;
}
var actualName = name.GetNameVariants(Culture).FirstOrDefault(n => data.ContainsKey(n));
var value = actualName != null ? data[actualName] : null;
if (value == null) continue;
prop.SetValue(target, ConvertValue(type, value), null);
}
}
private IDictionary BuildDictionary(Type type, object parent)
{
var dict = (IDictionary)Activator.CreateInstance(type);
var valueType = type.GetGenericArguments()[1];
foreach (var child in (IDictionary<string, object>)parent)
{
var key = child.Key;
object item = null;
if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>))
{
item = BuildList(valueType, child.Value);
}
else
{
item = ConvertValue(valueType, child.Value);
}
dict.Add(key, item);
}
return dict;
}
private IList BuildList(Type type, object parent)
{
var list = (IList)Activator.CreateInstance(type);
var listType = type.GetInterfaces().First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>));
var itemType = listType.GetGenericArguments()[0];
if (parent is IList)
{
foreach (var element in (IList)parent)
{
if (itemType.IsPrimitive)
{
var value = element.ToString();
list.Add(value.ChangeType(itemType, Culture));
}
else if (itemType == typeof(string))
{
if (element == null)
{
list.Add(null);
continue;
}
list.Add(element.ToString());
}
else
{
if (element == null)
{
list.Add(null);
continue;
}
var item = ConvertValue(itemType, element);
list.Add(item);
}
}
}
else
{
list.Add(ConvertValue(itemType, parent));
}
return list;
}
private object ConvertValue(Type type, object value)
{
var stringValue = Convert.ToString(value, Culture);
// check for nullable and extract underlying type
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// Since the type is nullable and no value is provided return null
if (String.IsNullOrEmpty(stringValue)) return null;
type = type.GetGenericArguments()[0];
}
if (type == typeof(System.Object) && value != null)
{
type = value.GetType();
}
if (type.IsPrimitive)
{
return value.ChangeType(type, Culture);
}
else if (type.IsEnum)
{
return type.FindEnumValue(stringValue, Culture);
}
else if (type == typeof(Uri))
{
return new Uri(stringValue, UriKind.RelativeOrAbsolute);
}
else if (type == typeof(string))
{
return stringValue;
}
else if (type == typeof(DateTime)
#if !PocketPC
|| type == typeof(DateTimeOffset)
#endif
)
{
DateTime dt;
if (DateFormat.HasValue())
{
dt = DateTime.ParseExact(stringValue, DateFormat, Culture);
}
else
{
// try parsing instead
dt = stringValue.ParseJsonDate(Culture);
}
#if PocketPC
return dt;
#else
if (type == typeof(DateTime))
{
return dt;
}
else if (type == typeof(DateTimeOffset))
{
return (DateTimeOffset)dt;
}
#endif
}
else if (type == typeof(Decimal))
{
if (value is double)
return (decimal)((double)value);
return Decimal.Parse(stringValue, Culture);
}
else if (type == typeof(Guid))
{
return string.IsNullOrEmpty(stringValue) ? Guid.Empty : new Guid(stringValue);
}
else if (type == typeof(TimeSpan))
{
return TimeSpan.Parse(stringValue);
}
else if (type.IsGenericType)
{
var genericTypeDef = type.GetGenericTypeDefinition();
if (genericTypeDef == typeof(List<>))
{
return BuildList(type, value);
}
else if (genericTypeDef == typeof(Dictionary<,>))
{
var keyType = type.GetGenericArguments()[0];
// only supports Dict<string, T>()
if (keyType == typeof(string))
{
return BuildDictionary(type, value);
}
}
else
{
// nested property classes
return CreateAndMap(type, value);
}
}
else
{
// nested property classes
return CreateAndMap(type, value);
}
return null;
}
private object CreateAndMap(Type type, object element)
{
var instance = Activator.CreateInstance(type);
Map(instance, (IDictionary<string, object>)element);
return instance;
}
}
}
XmlDeserializer:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using RestSharp.Extensions;
using System.Globalization;
using System.Xml;
using System.ComponentModel;
namespace myCompany
{
public class XmlDeserializer : IDeserializer
{
public string RootElement { get; set; }
public string Namespace { get; set; }
public string DateFormat { get; set; }
public CultureInfo Culture { get; set; }
public XmlDeserializer()
{
Culture = CultureInfo.InvariantCulture;
}
public virtual T Deserialize<T>(IRestResponse response)
{
if (string.IsNullOrEmpty( response.Content ))
return default(T);
var doc = XDocument.Parse(response.Content);
var root = doc.Root;
if (RootElement.HasValue() && doc.Root != null)
{
root = doc.Root.Element(RootElement.AsNamespaced(Namespace));
}
// autodetect xml namespace
if (!Namespace.HasValue())
{
RemoveNamespace(doc);
}
var x = Activator.CreateInstance<T>();
var objType = x.GetType();
if (objType.IsSubclassOfRawGeneric(typeof(List<>)))
{
x = (T)HandleListDerivative(x, root, objType.Name, objType);
}
else
{
Map(x, root);
}
return x;
}
private void RemoveNamespace(XDocument xdoc)
{
foreach (XElement e in xdoc.Root.DescendantsAndSelf())
{
if (e.Name.Namespace != XNamespace.None)
{
e.Name = XNamespace.None.GetName(e.Name.LocalName);
}
if (e.Attributes().Any(a => a.IsNamespaceDeclaration || a.Name.Namespace != XNamespace.None))
{
e.ReplaceAttributes(e.Attributes().Select(a => a.IsNamespaceDeclaration ? null : a.Name.Namespace != XNamespace.None ? new XAttribute(XNamespace.None.GetName(a.Name.LocalName), a.Value) : a));
}
}
}
protected virtual void Map(object x, XElement root)
{
var objType = x.GetType();
var props = objType.GetProperties();
foreach (var prop in props)
{
var type = prop.PropertyType;
if (!type.IsPublic || !prop.CanWrite)
continue;
var name = prop.Name.AsNamespaced(Namespace);
var value = GetValueFromXml(root, name, prop);
if (value == null)
{
// special case for inline list items
if (type.IsGenericType)
{
var genericType = type.GetGenericArguments()[0];
var first = GetElementByName(root, genericType.Name);
var list = (IList)Activator.CreateInstance(type);
if (first != null)
{
var elements = root.Elements(first.Name);
PopulateListFromElements(genericType, elements, list);
}
prop.SetValue(x, list, null);
}
continue;
}
// check for nullable and extract underlying type
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// if the value is empty, set the property to null...
if (value == null || String.IsNullOrEmpty(value.ToString()))
{
prop.SetValue(x, null, null);
continue;
}
type = type.GetGenericArguments()[0];
}
if (type == typeof(bool))
{
var toConvert = value.ToString().ToLower();
prop.SetValue(x, XmlConvert.ToBoolean(toConvert), null);
}
else if (type.IsPrimitive)
{
prop.SetValue(x, value.ChangeType(type, Culture), null);
}
else if (type.IsEnum)
{
var converted = type.FindEnumValue(value.ToString(), Culture);
prop.SetValue(x, converted, null);
}
else if (type == typeof(Uri))
{
var uri = new Uri(value.ToString(), UriKind.RelativeOrAbsolute);
prop.SetValue(x, uri, null);
}
else if (type == typeof(string))
{
prop.SetValue(x, value, null);
}
else if (type == typeof(DateTime))
{
if (DateFormat.HasValue())
{
value = DateTime.ParseExact(value.ToString(), DateFormat, Culture);
}
else
{
value = DateTime.Parse(value.ToString(), Culture);
}
prop.SetValue(x, value, null);
}
#if !PocketPC
else if (type == typeof(DateTimeOffset))
{
var toConvert = value.ToString();
if (!string.IsNullOrEmpty(toConvert))
{
DateTimeOffset deserialisedValue;
try
{
deserialisedValue = XmlConvert.ToDateTimeOffset(toConvert);
prop.SetValue(x, deserialisedValue, null);
}
catch (Exception)
{
object result;
if (TryGetFromString(toConvert, out result, type))
{
prop.SetValue(x, result, null);
}
else
{
//fallback to parse
deserialisedValue = DateTimeOffset.Parse(toConvert);
prop.SetValue(x, deserialisedValue, null);
}
}
}
}
#endif
else if (type == typeof(Decimal))
{
value = Decimal.Parse(value.ToString(), Culture);
prop.SetValue(x, value, null);
}
else if (type == typeof(Guid))
{
var raw = value.ToString();
value = string.IsNullOrEmpty(raw) ? Guid.Empty : new Guid(value.ToString());
prop.SetValue(x, value, null);
}
else if (type == typeof(TimeSpan))
{
var timeSpan = XmlConvert.ToTimeSpan(value.ToString());
prop.SetValue(x, timeSpan, null);
}
else if (type.IsGenericType)
{
var t = type.GetGenericArguments()[0];
var list = (IList)Activator.CreateInstance(type);
var container = GetElementByName(root, prop.Name.AsNamespaced(Namespace));
if (container.HasElements)
{
var first = container.Elements().FirstOrDefault();
var elements = container.Elements(first.Name);
PopulateListFromElements(t, elements, list);
}
prop.SetValue(x, list, null);
}
else if (type.IsSubclassOfRawGeneric(typeof(List<>)))
{
// handles classes that derive from List<T>
// e.g. a collection that also has attributes
var list = HandleListDerivative(x, root, prop.Name, type);
prop.SetValue(x, list, null);
}
else
{
//fallback to type converters if possible
object result;
if (TryGetFromString(value.ToString(), out result, type))
{
prop.SetValue(x, result, null);
}
else
{
// nested property classes
if (root != null)
{
var element = GetElementByName(root, name);
if (element != null)
{
var item = CreateAndMap(type, element);
prop.SetValue(x, item, null);
}
}
}
}
}
}
private static bool TryGetFromString(string inputString, out object result, Type type)
{
#if !SILVERLIGHT && !WINDOWS_PHONE && !PocketPC
var converter = TypeDescriptor.GetConverter(type);
if (converter.CanConvertFrom(typeof(string)))
{
result = (converter.ConvertFromInvariantString(inputString));
return true;
}
result = null;
return false;
#else
result = null;
return false;
#endif
}
private void PopulateListFromElements(Type t, IEnumerable<XElement> elements, IList list)
{
foreach (var element in elements)
{
var item = CreateAndMap(t, element);
list.Add(item);
}
}
private object HandleListDerivative(object x, XElement root, string propName, Type type)
{
Type t;
if (type.IsGenericType)
{
t = type.GetGenericArguments()[0];
}
else
{
t = type.BaseType.GetGenericArguments()[0];
}
var list = (IList)Activator.CreateInstance(type);
var elements = root.Descendants(t.Name.AsNamespaced(Namespace));
var name = t.Name;
if (!elements.Any())
{
var lowerName = name.ToLower().AsNamespaced(Namespace);
elements = root.Descendants(lowerName);
}
if (!elements.Any())
{
var camelName = name.ToCamelCase(Culture).AsNamespaced(Namespace);
elements = root.Descendants(camelName);
}
if (!elements.Any())
{
elements = root.Descendants().Where(e => e.Name.LocalName.RemoveUnderscoresAndDashes() == name);
}
if (!elements.Any())
{
var lowerName = name.ToLower().AsNamespaced(Namespace);
elements = root.Descendants().Where(e => e.Name.LocalName.RemoveUnderscoresAndDashes() == lowerName);
}
PopulateListFromElements(t, elements, list);
// get properties too, not just list items
// only if this isn't a generic type
if (!type.IsGenericType)
{
Map(list, root.Element(propName.AsNamespaced(Namespace)) ?? root); // when using RootElement, the heirarchy is different
}
return list;
}
protected virtual object CreateAndMap(Type t, XElement element)
{
object item;
if (t == typeof(String))
{
item = element.Value;
}
else if (t.IsPrimitive)
{
item = element.Value.ChangeType(t, Culture);
}
else
{
item = Activator.CreateInstance(t);
Map(item, element);
}
return item;
}
protected virtual object GetValueFromXml(XElement root, XName name, PropertyInfo prop)
{
object val = null;
if (root != null)
{
var element = GetElementByName(root, name);
if (element == null)
{
var attribute = GetAttributeByName(root, name);
if (attribute != null)
{
val = attribute.Value;
}
}
else
{
if (!element.IsEmpty || element.HasElements || element.HasAttributes)
{
val = element.Value;
}
}
}
return val;
}
protected virtual XElement GetElementByName(XElement root, XName name)
{
var lowerName = name.LocalName.ToLower().AsNamespaced(name.NamespaceName);
var camelName = name.LocalName.ToCamelCase(Culture).AsNamespaced(name.NamespaceName);
if (root.Element(name) != null)
{
return root.Element(name);
}
if (root.Element(lowerName) != null)
{
return root.Element(lowerName);
}
if (root.Element(camelName) != null)
{
return root.Element(camelName);
}
if (name == "Value".AsNamespaced(name.NamespaceName))
{
return root;
}
// try looking for element that matches sanitized property name (Order by depth)
var element = root.Descendants()
.OrderBy(d => d.Ancestors().Count())
.FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name.LocalName)
?? root.Descendants()
.OrderBy(d => d.Ancestors().Count())
.FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name.LocalName.ToLower());
if (element != null)
{
return element;
}
return null;
}
protected virtual XAttribute GetAttributeByName(XElement root, XName name)
{
var lowerName = name.LocalName.ToLower().AsNamespaced(name.NamespaceName);
var camelName = name.LocalName.ToCamelCase(Culture).AsNamespaced(name.NamespaceName);
if (root.Attribute(name) != null)
{
return root.Attribute(name);
}
if (root.Attribute(lowerName) != null)
{
return root.Attribute(lowerName);
}
if (root.Attribute(camelName) != null)
{
return root.Attribute(camelName);
}
// try looking for element that matches sanitized property name
var element = root.Attributes().FirstOrDefault(d => d.Name.LocalName.RemoveUnderscoresAndDashes() == name.LocalName);
if (element != null)
{
return element;
}
return null;
}
}
}
DotNetXmlDeserializer:
using System.IO;
using System.Text;
namespace myCompany
{
public class DotNetXmlDeserializer : IDeserializer
{
public string DateFormat { get; set; }
public string Namespace { get; set; }
public string RootElement { get; set; }
public T Deserialize<T>(IRestResponse response)
{
if (string.IsNullOrEmpty(response.Content))
{
return default(T);
}
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(response.Content)))
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stream);
}
}
}
}
20. 常用扩展方法(持续更新)
using System.IO;
using System.Text;
namespace myCompany.Helper
{
/*
* 与Stream和byte[]有关的扩展方法
*/
public static class DataExtensions
{
/*
* 把字符串用UTF8流Stream输出
* 用法: context.Response.OutputStream.WriteStringUtf8(
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Response>
<Error>
<Message>Not found!</Message>
</Error>
</Response>");
*/
public static void WriteStringUtf8(this Stream target, string value)
{
var encoded = Encoding.UTF8.GetBytes(value);
target.Write(encoded, 0, encoded.Length);
}
//把字节流byte[]另存为文件
public static void SaveAs(this byte[] input, string path)
{
File.WriteAllBytes(path, input);
}
//流Stream读为 byte[]
public static byte[] ReadAsBytes(this Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
//Stream CopyTo方法
public static void CopyTo(this Stream input, Stream output)
{
var buffer = new byte[32768];
while(true)
{
var read = input.Read(buffer, 0, buffer.Length);
if(read <= 0)
return;
output.Write(buffer, 0, read);
}
}
//byte[]转换为字符串
public static string AsString(this byte[] buffer)
{
if (buffer == null) return "";
// Ansi as default
Encoding encoding = Encoding.UTF8;
return encoding.GetString(buffer, 0, buffer.Length);
}
}
/*
* 与反射/Reflection有关的扩展方法
*/
public static class ReflectionExtensions
{
/// <summary>
/// Retrieve an attribute from a member (property)
/// </summary>
/// <typeparam name="T">Type of attribute to retrieve</typeparam>
/// <param name="prop">Member to retrieve attribute from</param>
/// <returns></returns>
public static T GetAttribute<T>(this MemberInfo prop) where T : Attribute {
return Attribute.GetCustomAttribute(prop, typeof(T)) as T;
}
/// <summary>
/// Retrieve an attribute from a type
/// </summary>
/// <typeparam name="T">Type of attribute to retrieve</typeparam>
/// <param name="type">Type to retrieve attribute from</param>
/// <returns></returns>
public static T GetAttribute<T>(this Type type) where T : Attribute {
return Attribute.GetCustomAttribute(type, typeof(T)) as T;
}
/// <summary>
/// Checks a type to see if it derives from a raw generic (e.g. List[[]])
/// </summary>
/// <param name="toCheck"></param>
/// <param name="generic"></param>
/// <returns></returns>
public static bool IsSubclassOfRawGeneric(this Type toCheck, Type generic) {
while (toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
public static object ChangeType(this object source, Type newType)
{
return Convert.ChangeType(source, newType);
}
public static object ChangeType(this object source, Type newType, CultureInfo culture)
{
return Convert.ChangeType(source, newType, culture);
}
/// <summary>
/// Find a value from a System.Enum by trying several possible variants
/// of the string value of the enum.
/// </summary>
/// <param name="type">Type of enum</param>
/// <param name="value">Value for which to search</param>
/// <param name="culture">The culture used to calculate the name variants</param>
/// <returns></returns>
public static object FindEnumValue(this Type type, string value, CultureInfo culture)
{
var ret = Enum.GetValues( type )
.Cast<Enum>()
.FirstOrDefault(v => v.ToString().GetNameVariants(culture).Contains(value, StringComparer.Create(culture, true)));
if (ret == null)
{
var enumValueAsUnderlyingType = Convert.ChangeType(value, Enum.GetUnderlyingType(type), culture);
if (enumValueAsUnderlyingType != null && Enum.IsDefined(type, enumValueAsUnderlyingType))
{
ret = (Enum) Enum.ToObject(type, enumValueAsUnderlyingType);
}
}
return ret;
}
}
/*
* 与String字符串有关的扩展方法
*/
public static class StringExtensions
{
public static bool IsNullOrBlank(this string value)
{
return String.IsNullOrEmpty(value) ||
(!String.IsNullOrEmpty(value) && value.Trim() == String.Empty);
}
public static bool EqualsIgnoreCase(this string left, string right)
{
return String.Compare(left, right, StringComparison.OrdinalIgnoreCase) == 0;
}
public static bool EqualsAny(this string input, params string[] args)
{
return args.Aggregate(false, (current, arg) => current | input.Equals(arg));
}
public static string FormatWith(this string format, params object[] args)
{
return String.Format(format, args);
}
public static string FormatWithInvariantCulture(this string format, params object[] args)
{
return String.Format(CultureInfo.InvariantCulture, format, args);
}
public static string Then(this string input, string value)
{
return String.Concat(input, value);
}
public static string UrlEncode(this string value)
{
// [DC] This is more correct than HttpUtility; it escapes spaces as %20, not +
return Uri.EscapeDataString(value);
}
public static string UrlDecode(this string value)
{
return Uri.UnescapeDataString(value);
}
public static Uri AsUri(this string value)
{
return new Uri(value);
}
public static string ToBase64String(this byte[] input)
{
return Convert.ToBase64String(input);
}
public static byte[] GetBytes(this string input)
{
return Encoding.UTF8.GetBytes(input);
}
public static string PercentEncode(this string s)
{
var bytes = s.GetBytes();
var sb = new StringBuilder();
foreach (var b in bytes)
{
// [DC]: Support proper encoding of special characters (\n\r\t\b)
if ((b > 7 && b < 11) || b == 13)
{
sb.Append(string.Format("%0{0:X}", b));
}
else
{
sb.Append(string.Format("%{0:X}", b));
}
}
return sb.ToString();
}
public static IDictionary<string, string> ParseQueryString(this string query)
{
// [DC]: This method does not URL decode, and cannot handle decoded input
if (query.StartsWith("?")) query = query.Substring(1);
if (query.Equals(string.Empty))
{
return new Dictionary<string, string>();
}
var parts = query.Split(new[] {'&'});
return parts.Select(
part => part.Split(new[] {'='})).ToDictionary(
pair => pair[0], pair => pair[1]
);
}
public static string UrlDecode(this string input)
{
return HttpUtility.UrlDecode(input);
}
/// <summary>
/// Uses Uri.EscapeDataString() based on recommendations on MSDN
/// http://blogs.msdn.com/b/yangxind/archive/2006/11/09/don-t-use-net-system-uri-unescapedatastring-in-url-decoding.aspx
/// </summary>
public static string UrlEncode(this string input)
{
const int maxLength = 32766;
if (input == null)
throw new ArgumentNullException("input");
if (input.Length <= maxLength)
return Uri.EscapeDataString(input);
StringBuilder sb = new StringBuilder(input.Length * 2);
int index = 0;
while (index < input.Length)
{
int length = Math.Min(input.Length - index, maxLength);
string subString = input.Substring(index, length);
sb.Append(Uri.EscapeDataString(subString));
index += subString.Length;
}
return sb.ToString();
}
public static string HtmlDecode(this string input)
{
return HttpUtility.HtmlDecode(input);
}
public static string HtmlEncode(this string input)
{
return HttpUtility.HtmlEncode(input);
}
public static string HtmlAttributeEncode(this string input)
{
return HttpUtility.HtmlAttributeEncode(input);
}
/// <summary>
/// Check that a string is not null or empty
/// </summary>
/// <param name="input">String to check</param>
/// <returns>bool</returns>
public static bool HasValue(this string input)
{
return !string.IsNullOrEmpty(input);
}
/// <summary>
/// Remove underscores from a string
/// </summary>
/// <param name="input">String to process</param>
/// <returns>string</returns>
public static string RemoveUnderscoresAndDashes(this string input)
{
return input.Replace("_", "").Replace("-", ""); // avoiding regex
}
/// <summary>
/// Parses most common JSON date formats
/// </summary>
/// <param name="input">JSON value to parse</param>
/// <returns>DateTime</returns>
public static DateTime ParseJsonDate(this string input, CultureInfo culture)
{
input = input.Replace("\n", "");
input = input.Replace("\r", "");
input = input.RemoveSurroundingQuotes();
long? unix = null;
try {
unix = Int64.Parse(input);
} catch (Exception) { };
if (unix.HasValue)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddSeconds(unix.Value);
}
if (input.Contains("/Date("))
{
return ExtractDate(input, @"\\?/Date\((-?\d+)(-|\+)?([0-9]{4})?\)\\?/", culture);
}
if (input.Contains("new Date("))
{
input = input.Replace(" ", "");
// because all whitespace is removed, match against newDate( instead of new Date(
return ExtractDate(input, @"newDate\((-?\d+)*\)", culture);
}
return ParseFormattedDate(input, culture);
}
/// <summary>
/// Remove leading and trailing " from a string
/// </summary>
/// <param name="input">String to parse</param>
/// <returns>String</returns>
public static string RemoveSurroundingQuotes(this string input)
{
if (input.StartsWith("\"") && input.EndsWith("\""))
{
// remove leading/trailing quotes
input = input.Substring(1, input.Length - 2);
}
return input;
}
private static DateTime ParseFormattedDate(string input, CultureInfo culture)
{
var formats = new[] {
"u",
"s",
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'",
"yyyy-MM-ddTHH:mm:ssZ",
"yyyy-MM-dd HH:mm:ssZ",
"yyyy-MM-ddTHH:mm:ss",
"yyyy-MM-ddTHH:mm:sszzzzzz",
"M/d/yyyy h:mm:ss tt" // default format for invariant culture
};
DateTime date;
if (DateTime.TryParseExact(input, formats, culture, DateTimeStyles.None, out date))
{
return date;
}
if (DateTime.TryParse(input, culture, DateTimeStyles.None, out date))
{
return date;
}
return default(DateTime);
}
private static DateTime ExtractDate(string input, string pattern, CultureInfo culture)
{
DateTime dt = DateTime.MinValue;
var regex = new Regex(pattern);
if (regex.IsMatch(input))
{
var matches = regex.Matches(input);
var match = matches[0];
var ms = Convert.ToInt64(match.Groups[1].Value);
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
dt = epoch.AddMilliseconds(ms);
// adjust if time zone modifier present
if (match.Groups.Count > 2 && !String.IsNullOrEmpty(match.Groups[3].Value))
{
var mod = DateTime.ParseExact(match.Groups[3].Value, "HHmm", culture);
if (match.Groups[2].Value == "+")
{
dt = dt.Add(mod.TimeOfDay);
}
else
{
dt = dt.Subtract(mod.TimeOfDay);
}
}
}
return dt;
}
/// <summary>
/// Checks a string to see if it matches a regex
/// </summary>
/// <param name="input">String to check</param>
/// <param name="pattern">Pattern to match</param>
/// <returns>bool</returns>
public static bool Matches(this string input, string pattern)
{
return Regex.IsMatch(input, pattern);
}
/// <summary>
/// Converts a string to pascal case
/// </summary>
/// <param name="lowercaseAndUnderscoredWord">String to convert</param>
/// <returns>string</returns>
public static string ToPascalCase(this string lowercaseAndUnderscoredWord, CultureInfo culture)
{
return ToPascalCase(lowercaseAndUnderscoredWord, true, culture);
}
/// <summary>
/// Converts a string to pascal case with the option to remove underscores
/// </summary>
/// <param name="text">String to convert</param>
/// <param name="removeUnderscores">Option to remove underscores</param>
/// <returns></returns>
public static string ToPascalCase(this string text, bool removeUnderscores, CultureInfo culture)
{
if (String.IsNullOrEmpty(text))
return text;
text = text.Replace("_", " ");
string joinString = removeUnderscores ? String.Empty : "_";
string[] words = text.Split(' ');
if (words.Length > 1 || words[0].IsUpperCase())
{
for (int i = 0; i < words.Length; i++)
{
if (words[i].Length > 0)
{
string word = words[i];
string restOfWord = word.Substring(1);
if (restOfWord.IsUpperCase())
restOfWord = restOfWord.ToLower(culture);
char firstChar = char.ToUpper(word[0], culture);
words[i] = String.Concat(firstChar, restOfWord);
}
}
return String.Join(joinString, words);
}
return String.Concat(words[0].Substring(0, 1).ToUpper(culture), words[0].Substring(1));
}
/// <summary>
/// Converts a string to camel case
/// </summary>
/// <param name="lowercaseAndUnderscoredWord">String to convert</param>
/// <returns>String</returns>
public static string ToCamelCase(this string lowercaseAndUnderscoredWord, CultureInfo culture)
{
return MakeInitialLowerCase(ToPascalCase(lowercaseAndUnderscoredWord, culture));
}
/// <summary>
/// Convert the first letter of a string to lower case
/// </summary>
/// <param name="word">String to convert</param>
/// <returns>string</returns>
public static string MakeInitialLowerCase(this string word)
{
return String.Concat(word.Substring(0, 1).ToLower(), word.Substring(1));
}
/// <summary>
/// Checks to see if a string is all uppper case
/// </summary>
/// <param name="inputString">String to check</param>
/// <returns>bool</returns>
public static bool IsUpperCase(this string inputString)
{
return Regex.IsMatch(inputString, @"^[A-Z]+$");
}
/// <summary>
/// Add underscores to a pascal-cased string
/// </summary>
/// <param name="pascalCasedWord">String to convert</param>
/// <returns>string</returns>
public static string AddUnderscores(this string pascalCasedWord)
{
return
Regex.Replace(
Regex.Replace(Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1_$2"), @"([a-z\d])([A-Z])",
"$1_$2"), @"[-\s]", "_");
}
/// <summary>
/// Add dashes to a pascal-cased string
/// </summary>
/// <param name="pascalCasedWord">String to convert</param>
/// <returns>string</returns>
public static string AddDashes(this string pascalCasedWord)
{
return
Regex.Replace(
Regex.Replace(
Regex.Replace(pascalCasedWord, @"([A-Z]+)([A-Z][a-z])", "$1-$2"),
@"([a-z\d])([A-Z])",
"$1-$2"), @"[\s]", "-");
}
/// <summary>
/// Add an undescore prefix to a pascasl-cased string
/// </summary>
/// <param name="pascalCasedWord"></param>
/// <returns></returns>
public static string AddUnderscorePrefix(this string pascalCasedWord)
{
return string.Format("_{0}", pascalCasedWord);
}
/// <summary>
/// Return possible variants of a name for name matching.
/// </summary>
/// <param name="name">String to convert</param>
/// <param name="culture">The culture to use for conversion</param>
/// <returns>IEnumerable<string></returns>
public static IEnumerable<string> GetNameVariants(this string name, CultureInfo culture)
{
if (String.IsNullOrEmpty(name))
yield break;
yield return name;
// try camel cased name
yield return name.ToCamelCase(culture);
// try lower cased name
yield return name.ToLower(culture);
// try name with underscores
yield return name.AddUnderscores();
// try name with underscores with lower case
yield return name.AddUnderscores().ToLower(culture);
// try name with dashes
yield return name.AddDashes();
// try name with dashes with lower case
yield return name.AddDashes().ToLower(culture);
// try name with underscore prefix
yield return name.AddUnderscorePrefix();
// try name with underscore prefix, using camel case
yield return name.ToCamelCase(culture).AddUnderscorePrefix();
}
}
/*
* 与XML有关的扩展方法
*/
public static class XmlExtensions
{
/// <summary>
/// Returns the name of an element with the namespace if specified
/// </summary>
/// <param name="name">Element name</param>
/// <param name="namespace">XML Namespace</param>
/// <returns></returns>
public static XName AsNamespaced(this string name, string @namespace) {
XName xName = name;
if (@namespace.HasValue())
xName = XName.Get(name, @namespace);
return xName;
}
}
/*
* 与日期Datatime有关的扩展方法
*/
public static class TimeExtensions
{
public static DateTime FromNow(this TimeSpan value)
{
return new DateTime((DateTime.Now + value).Ticks);
}
public static DateTime FromUnixTime(this long seconds)
{
var time = new DateTime(1970, 1, 1);
time = time.AddSeconds(seconds);
return time.ToLocalTime();
}
public static long ToUnixTime(this DateTime dateTime)
{
var timeSpan = (dateTime - new DateTime(1970, 1, 1));
var timestamp = (long) timeSpan.TotalSeconds;
return timestamp;
}
}
/*
* 与集合Collection有关的扩展方法
*/
public internal static class CollectionExtensions
{
public static IEnumerable<T> AsEnumerable<T>(this T item)
{
return new[] {item};
}
public static IEnumerable<T> And<T>(this T item, T other)
{
return new[] {item, other};
}
public static IEnumerable<T> And<T>(this IEnumerable<T> items, T item)
{
foreach (var i in items)
{
yield return i;
}
yield return item;
}
public static K TryWithKey<T, K>(this IDictionary<T, K> dictionary, T key)
{
return dictionary.ContainsKey(key) ? dictionary[key] : default(K);
}
public static IEnumerable<T> ToEnumerable<T>(this object[] items) where T : class
{
foreach (var item in items)
{
var record = item as T;
yield return record;
}
}
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
foreach (var item in items)
{
action(item);
}
}
public static void AddRange(this IDictionary<string, string> collection, NameValueCollection range)
{
foreach (var key in range.AllKeys)
{
collection.Add(key, range[key]);
}
}
public static string ToQueryString(this NameValueCollection collection)
{
var sb = new StringBuilder();
if (collection.Count > 0)
{
sb.Append("?");
}
var count = 0;
foreach (var key in collection.AllKeys)
{
sb.AppendFormat("{0}={1}", key, collection[key].UrlEncode());
count++;
if (count >= collection.Count)
{
continue;
}
sb.Append("&");
}
return sb.ToString();
}
public static string Concatenate(this WebParameterCollection collection, string separator, string spacer)
{
var sb = new StringBuilder();
var total = collection.Count;
var count = 0;
foreach (var item in collection)
{
sb.Append(item.Name);
sb.Append(separator);
sb.Append(item.Value);
count++;
if (count < total)
{
sb.Append(spacer);
}
}
return sb.ToString();
}
}
}