//******************************************************************************************************
// Common.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 04/03/2006 - J. Ritchie Carroll
// Generated original version of source code.
// 12/13/2007 - Darrell Zuercher
// Edited code comments.
// 09/08/2008 - J. Ritchie Carroll
// Converted to C#.
// 02/13/2009 - Josh L. Patterson
// Edited Code Comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 09/17/2009 - Pinal C. Patel
// Modified GetApplicationType() to remove dependency on HttpContext.Current.
// 09/28/2010 - Pinal C. Patel
// Cached the current ApplicationType returned by GetApplicationType() for better performance.
// 12/05/2010 - Pinal C. Patel
// Added an overload for TypeConvertToString() that takes CultureInfo as a parameter.
// 12/07/2010 - Pinal C. Patel
// Updated TypeConvertToString() to return an empty string if the passed in value is null.
// 03/09/2011 - Pinal C. Patel
// Moved UpdateType enumeration from GSF.Services.ServiceProcess namespace for broader usage.
// 04/07/2011 - J. Ritchie Carroll
// Added ToNonNullNorEmptyString() and ToNonNullNorWhiteSpace() extensions.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
namespace GSF
{
// This is the location for handy miscellaneous functions that are difficult to categorize elsewhere. For the most
// part these functions may have the most value in a Visual Basic application which supports importing functions
// down to a class level, e.g.: Imports GSF.Common
///
/// Defines common global functions.
///
public static partial class Common
{
///
/// Determines if the current system is a POSIX style environment.
///
///
///
/// Since a .NET application compiled under Mono can run under both Windows and Unix style platforms,
/// you can use this property to easily determine the current operating environment.
///
///
/// This property will return true for both MacOSX and Unix environments. Use the Platform property
/// of the to determine more specific platform type, e.g.,
/// MacOSX or Unix. Note that all flavors of Linux will show up as .
///
///
public static readonly bool IsPosixEnvironment = Path.DirectorySeparatorChar == '/'; // This is how Mono source often checks this
///
/// Determines if the code base is currently running under Mono.
///
///
/// This property can be used to make a run-time determination if Windows or Mono based .NET is being used. However, it is
/// highly recommended to use the MONO compiler directive wherever possible instead of determining this at run-time.
///
public static bool IsMono = (object)Type.GetType("Mono.Runtime") != null;
/// Returns one of two strongly-typed objects.
/// One of two objects, depending on the evaluation of given expression.
/// The expression you want to evaluate.
/// Returned if expression evaluates to True.
/// Returned if expression evaluates to False.
/// Return type used for immediate expression
///
/// This function acts as a strongly-typed immediate if (a.k.a. inline if).
///
/// It is expected that this function will only be used in languages that do not support ?: conditional operations, e.g., Visual Basic.NET.
/// In Visual Basic this function can be used as a strongly-typed IIf replacement by specifying "Imports GSF.Common".
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T IIf(bool expression, T truePart, T falsePart)
{
return expression ? truePart : falsePart;
}
/// Creates a strongly-typed Array.
/// New array of specified type.
/// Desired length of new array.
/// Return type for new array.
///
/// It is expected that this function will only be used in Visual Basic.NET.
///
/// The Array.CreateInstance provides better performance and more direct CLR access for array creation (not to
/// mention less confusion on the matter of array lengths) in VB.NET, however the returned System.Array is not
/// typed properly. This function properly casts the return array based on the type specification helping
/// when Option Strict is enabled.
///
///
///
///
/// Dim buffer As Byte() = CreateArray(Of Byte)(12)
/// Dim matrix As Integer()() = CreateArray(Of Integer())(10)
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] CreateArray(int length)
{
// The following provides better performance than "Return New T(length) {}".
// ReSharper disable once UseArrayCreationExpression.1
return (T[])Array.CreateInstance(typeof(T), length);
}
/// Creates a strongly-typed Array with an initial value parameter.
/// New array of specified type.
/// Desired length of new array.
/// Value used to initialize all array elements.
/// Return type for new array.
///
/// It is expected that this function will only be used in Visual Basic.NET.
///
///
///
/// Dim elements As Integer() = CreateArray(12, -1)
/// Dim names As String() = CreateArray(100, "undefined")
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] CreateArray(int length, T initialValue)
{
T[] typedArray = CreateArray(length);
// Initializes all elements with the default value.
for (int x = 0; x < typedArray.Length; x++)
{
typedArray[x] = initialValue;
}
return typedArray;
}
// The following "ToNonNullString" methods extend all class based objects. Note that these extension methods can be
// called even if the base object is null, hence the value of these methods. Our philosophy for this project has been
// "not" to apply extensions to all objects (this to avoid general namespace pollution) and make sure extensions are
// grouped together in their own source file (e.g., StringExtensions.cs); however these items do apply to all items
// and are essentially type-less hence their location in the "Common" class. These extension methods are at least
// limited to classes and won't show up on native types and custom structures.
///
/// Converts value to string; null objects (or DBNull objects) will return an empty string ("").
///
/// of to convert to string.
/// Value to convert to string.
/// as a string; if is null, empty string ("") will be returned.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToNonNullString(this T value) where T : class
{
return (object)value == null || value is DBNull ? "" : value.ToString();
}
///
/// Converts value to string; null objects (or DBNull objects) will return specified .
///
/// of to convert to string.
/// Value to convert to string.
/// to return if is null.
/// as a string; if is null, will be returned.
/// cannot be null.
public static string ToNonNullString(this T value, string nonNullValue) where T : class
{
if ((object)nonNullValue == null)
throw new ArgumentNullException(nameof(nonNullValue));
return (object)value == null || value is DBNull ? nonNullValue : value.ToString();
}
// We handle strings as a special version of the ToNullNullString extension to handle documentation a little differently
///
/// Makes sure returned string value is not null; if this string is null, empty string ("") will be returned.
///
/// to verify is not null.
/// value; if is null, empty string ("") will be returned.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToNonNullString(this string value)
{
return (object)value == null ? "" : value;
}
///
/// Converts value to string; null objects, DBNull objects or empty strings will return specified .
///
/// of to convert to string.
/// Value to convert to string.
/// to return if is null.
/// as a string; if is null, DBNull or an empty string will be returned.
/// must not be null or an empty string.
public static string ToNonNullNorEmptyString(this T value, string nonNullNorEmptyValue = " ") where T : class
{
if (string.IsNullOrEmpty(nonNullNorEmptyValue))
throw new ArgumentException("Must not be null or an empty string", nameof(nonNullNorEmptyValue));
if ((object)value == null || value is DBNull)
return nonNullNorEmptyValue;
string valueAsString = value.ToString();
return string.IsNullOrEmpty(valueAsString) ? nonNullNorEmptyValue : valueAsString;
}
///
/// Converts value to string; null objects, DBNull objects, empty strings or all white space strings will return specified .
///
/// of to convert to string.
/// Value to convert to string.
/// to return if is null.
/// as a string; if is null, DBNull, empty or all white space, will be returned.
/// must not be null, an empty string or white space.
public static string ToNonNullNorWhiteSpace(this T value, string nonNullNorWhiteSpaceValue = "_") where T : class
{
if (string.IsNullOrWhiteSpace(nonNullNorWhiteSpaceValue))
throw new ArgumentException("Must not be null, an empty string or white space", nameof(nonNullNorWhiteSpaceValue));
if ((object)value == null || value is DBNull)
return nonNullNorWhiteSpaceValue;
string valueAsString = value.ToString();
return string.IsNullOrWhiteSpace(valueAsString) ? nonNullNorWhiteSpaceValue : valueAsString;
}
///
/// Converts to a using an appropriate .
///
/// Value to convert to a .
/// converted to a .
///
///
/// If fails, the value's ToString() value will be returned.
/// Returned value will never be null, if no value exists an empty string ("") will be returned.
///
///
/// You can use the string extension
/// method or to convert the string back to its
/// original .
///
///
public static string TypeConvertToString(object value)
{
return TypeConvertToString(value, null);
}
///
/// Converts to a using an appropriate .
///
/// Value to convert to a .
/// to use for the conversion.
/// converted to a .
///
///
/// If fails, the value's ToString() value will be returned.
/// Returned value will never be null, if no value exists an empty string ("") will be returned.
///
///
/// You can use the string
/// extension method or to convert
/// the string back to its original .
///
///
public static string TypeConvertToString(object value, CultureInfo culture)
{
// Don't proceed further if value is null.
if ((object)value == null)
return string.Empty;
// If value is already a string, no need to attempt conversion
string valueAsString = value as string;
if ((object)valueAsString != null)
return valueAsString;
// Initialize culture info if not specified.
if ((object)culture == null)
culture = CultureInfo.InvariantCulture;
try
{
// Attempt to use type converter to set field value
TypeConverter converter = TypeDescriptor.GetConverter(value);
// ReSharper disable once AssignNullToNotNullAttribute
return converter.ConvertToString(null, culture, value).ToNonNullString();
}
catch
{
// Otherwise just call object's ToString method
return value.ToNonNullString();
}
}
///
/// Converts this string into the specified type.
///
/// Source string to convert to type.
/// to convert string to.
///
/// converted to specified ; default value of
/// specified type if conversion fails.
///
///
///
/// This function makes use of a to convert
/// to the specified , the best way to make sure
/// can be converted back to its original type is to use the same to
/// convert the original object to a ; see the
/// method for an easy way to do this.
///
///
/// This function varies from in that it
/// will use the default value for the parameter if
/// is empty or null.
///
///
public static object TypeConvertFromString(string value, Type type)
{
return TypeConvertFromString(value, type, null);
}
///
/// Converts this string into the specified type.
///
/// Source string to convert to type.
/// to convert string to.
/// to use for the conversion.
///
/// converted to specified ; default value of
/// specified type if conversion fails.
///
///
///
/// This function makes use of a to convert
/// to the specified , the best way to make sure
/// can be converted back to its original type is to use the same to
/// convert the original object to a ; see the
/// method for an easy way to do this.
///
///
/// This function varies from
/// in that it will use the default value for the parameter if
/// is empty or null.
///
///
public static object TypeConvertFromString(string value, Type type, CultureInfo culture)
{
if (string.IsNullOrWhiteSpace(value))
value = Activator.CreateInstance(type).ToString();
return value.ConvertToType(type, culture);
}
///
/// Gets a high-resolution number of seconds, including fractional seconds, that have
/// elapsed since 12:00:00 midnight, January 1, 0001.
///
public static double SystemTimer => Ticks.ToSeconds(DateTime.UtcNow.Ticks);
/// Determines if given item is equal to its default value (e.g., null or 0.0).
/// Object to evaluate.
/// Result of evaluation as a .
///
/// Native types default to zero, not null, therefore this can be used to evaluate if an item is its default (i.e., uninitialized) value.
///
public static bool IsDefaultValue(object item)
{
// Only reference types can be null, therefore null is its default value
if ((object)item == null)
return true;
Type itemType = item.GetType();
if (!itemType.IsValueType)
return false;
// Handle common types
IConvertible convertible = item as IConvertible;
if ((object)convertible != null)
{
try
{
switch (convertible.GetTypeCode())
{
case TypeCode.Boolean:
return (bool)item == default(bool);
case TypeCode.SByte:
return (sbyte)item == default(sbyte);
case TypeCode.Byte:
return (byte)item == default(byte);
case TypeCode.Int16:
return (short)item == default(short);
case TypeCode.UInt16:
return (ushort)item == default(ushort);
case TypeCode.Int32:
return (int)item == default(int);
case TypeCode.UInt32:
return (uint)item == default(uint);
case TypeCode.Int64:
return (long)item == default(long);
case TypeCode.UInt64:
return (ulong)item == default(ulong);
case TypeCode.Single:
return (float)item == default(float);
case TypeCode.Double:
return (double)item == default(double);
case TypeCode.Decimal:
return (decimal)item == default(decimal);
case TypeCode.Char:
return (char)item == default(char);
case TypeCode.DateTime:
return (DateTime)item == default(DateTime);
}
}
catch (InvalidCastException)
{
// An exception here indicates that the item is a custom type that
// lied about its type code. The type should still be instantiable,
// so we can ignore this exception
}
}
// Handle custom value types
return ((ValueType)item).Equals(Activator.CreateInstance(itemType));
}
/// Determines if given item is a reference type.
/// Object to evaluate.
/// Result of evaluation as a .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsReference(object item)
{
return !(item is ValueType);
}
/// Determines if given item is a reference type but not a string.
/// Object to evaluate.
/// Result of evaluation as a .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNonStringReference(object item)
{
return IsReference(item) && !(item is string);
}
///
/// Determines if is a numeric type, i.e., one of:
/// , , ,
/// , , ,
/// , ,
/// , or .
///
/// value to check.
/// true if is a numeric type; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNumericType(TypeCode typeCode)
{
switch (typeCode)
{
case TypeCode.Boolean:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return true;
}
return false;
}
///
/// Determines if is a numeric type, i.e., has a that is one of:
/// , , ,
/// , , ,
/// , ,
/// , or .
///
/// to check.
/// true if is a numeric type; otherwise, false.
public static bool IsNumericType(Type type) => IsNumericType(Type.GetTypeCode(type));
///
/// Determines if is a numeric type, i.e., has a that is one of:
/// , , ,
/// , , ,
/// , ,
/// , or .
///
/// to check.
/// true if is a numeric type; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static bool IsNumericType() => IsNumericType(Type.GetTypeCode(typeof(T)));
///
/// Determines if of is a numeric type, i.e.,
/// is and has a that is one of:
/// , , ,
/// , , ,
/// , ,
/// , or .
///
/// Object to evaluate.
/// true if is a numeric type; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNumericType(object item) => item is IConvertible convertible && IsNumericType(convertible.GetTypeCode());
///
/// Determines if given is or can be interpreted as numeric.
///
/// Object to evaluate.
/// true if is or can be interpreted as numeric; otherwise, false.
///
/// If type of is a or a , then if value can be parsed as a numeric
/// value, result will be true.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNumeric(object item)
{
if (IsNumericType(item))
return true;
return (item is char || item is string) && decimal.TryParse(item.ToString(), out _);
}
/// Returns the smallest item from a list of parameters.
/// Return type that is the minimum value in the .
/// A variable number of parameters of the specified type.
/// Result is the minimum value of type in the .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Min(params T[] itemList) => itemList.Min();
/// Returns the largest item from a list of parameters.
/// Return type that is the maximum value in the .
/// A variable number of parameters of the specified type .
/// Result is the maximum value of type in the .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Max(params T[] itemList) => itemList.Max();
/// Returns the value that is neither the largest nor the smallest.
/// of the objects passed to and returned from this method.
/// Value 1.
/// Value 2.
/// Value 3.
/// Result is the value that is neither the largest nor the smallest.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Mid(T value1, T value2, T value3) where T : IComparable
{
if ((object)value1 == null)
throw new ArgumentNullException(nameof(value1));
if ((object)value2 == null)
throw new ArgumentNullException(nameof(value2));
if ((object)value3 == null)
throw new ArgumentNullException(nameof(value3));
int comp1to2 = value1.CompareTo(value2);
int comp1to3 = value1.CompareTo(value3);
int comp2to3 = value2.CompareTo(value3);
// If 3 is the smallest, pick the smaller of 1 and 2
if (comp1to3 >= 0 && comp2to3 >= 0)
return comp1to2 <= 0 ? value1 : value2;
// If 2 is the smallest, pick the smaller of 1 and 3
if (comp1to2 >= 0 && comp2to3 <= 0)
return comp1to3 <= 0 ? value1 : value3;
// 1 is the smallest so pick the smaller of 2 and 3
return comp2to3 <= 0 ? value2 : value3;
}
///
/// Returns if not null; otherwise .
///
/// Value to test.
/// Value to return if primary value is null.
/// if not null; otherwise .
///
/// This function is useful when using evaluated code parsers based on older versions of .NET, e.g.,
/// the RazorEngine or the ExpressionEvaluator.
///
public static object NotNull(object value, object nonNullValue)
{
if (nonNullValue == null)
return new ArgumentNullException(nameof(nonNullValue));
return value == null || value is DBNull ? nonNullValue : value;
}
}
}