Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClrDynamic implements IConvertible explicitly #23

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 66 additions & 101 deletions ClrMD.Extensions/ClrDynamic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using ClrMD.Extensions.Core;
using ClrMD.Extensions.LINQPad;
using ClrMD.Extensions.Obfuscation;
using LINQPad;
using Microsoft.Diagnostics.Runtime;

namespace ClrMD.Extensions
{
public class ClrDynamic : DynamicObject, IEnumerable<ClrDynamic>, IComparable, ICustomMemberProvider
public class ClrDynamic : DynamicObject, IEnumerable<ClrDynamic>, IComparable, ICustomMemberProvider, IConvertible
{
public const ulong NullAddress = 0;
private const string ToStringFieldIndentation = " ";
Expand All @@ -25,7 +26,7 @@ public class ClrDynamic : DynamicObject, IEnumerable<ClrDynamic>, IComparable, I
public ulong Address { get; }

public ClrType Type { get; }

public bool IsInterior { get; }

public string TypeName => m_deobfuscator.OriginalName;
Expand Down Expand Up @@ -364,131 +365,69 @@ public int CompareTo(object other)
return Comparer.DefaultInvariant.Compare(left, right) <= 0;
}

#region Explicit Casts

public static bool operator true(ClrDynamic obj)
{
if (obj == null)
throw new ArgumentNullException("obj");

if (obj.HasSimpleValue)
return (bool)obj.SimpleValue;

throw new InvalidCastException(string.Format("Cannot cast type '{0}' to bool.", obj.Type));
return (bool)obj;
}

public static bool operator false(ClrDynamic obj)
{
if (obj == null)
throw new ArgumentNullException("obj");

if (obj.HasSimpleValue)
return !(bool)obj.SimpleValue;

throw new InvalidCastException(string.Format("Cannot cast type '{0}' to bool.", obj.Type));
return !obj;
}

public static bool operator !(ClrDynamic obj)
{
if (obj == null)
throw new ArgumentNullException("obj");

if (obj.HasSimpleValue)
return !(bool)obj.SimpleValue;

throw new InvalidCastException(string.Format("Cannot cast type '{0}' to bool.", obj.Type));
}

public static explicit operator bool(ClrDynamic obj)
{
return (bool)obj.SimpleValue;
}

public static explicit operator char(ClrDynamic obj)
{
return (char)obj.SimpleValue;
}

public static explicit operator sbyte(ClrDynamic obj)
{
return (sbyte)obj.SimpleValue;
}

public static explicit operator byte(ClrDynamic obj)
{
return (byte)obj.SimpleValue;
}

public static explicit operator short(ClrDynamic obj)
{
return (short)obj.SimpleValue;
}

public static explicit operator ushort(ClrDynamic obj)
{
return (ushort)obj.SimpleValue;
}

public static explicit operator int(ClrDynamic obj)
{
return (int)obj.SimpleValue;
}

public static explicit operator uint(ClrDynamic obj)
{
return (uint)obj.SimpleValue;
}

public static explicit operator long(ClrDynamic obj)
{
return (long)obj.SimpleValue;
}

public static explicit operator ulong(ClrDynamic obj)
{
return (ulong)obj.SimpleValue;
}

public static explicit operator float(ClrDynamic obj)
{
return (float)obj.SimpleValue;
}

public static explicit operator double(ClrDynamic obj)
{
return (double)obj.SimpleValue;
}
public static explicit operator bool(ClrDynamic obj) => Convert.ToBoolean(obj.SimpleValue);
public static explicit operator char(ClrDynamic obj) => Convert.ToChar(obj.SimpleValue);
public static explicit operator sbyte(ClrDynamic obj) => Convert.ToSByte(obj.SimpleValue);
public static explicit operator byte(ClrDynamic obj) => Convert.ToByte(obj.SimpleValue);
public static explicit operator short(ClrDynamic obj) => Convert.ToInt16(obj.SimpleValue);
public static explicit operator ushort(ClrDynamic obj) => Convert.ToUInt16(obj.SimpleValue);
public static explicit operator int(ClrDynamic obj) => Convert.ToInt32(obj.SimpleValue);
public static explicit operator uint(ClrDynamic obj) => Convert.ToUInt32(obj.SimpleValue);
public static explicit operator long(ClrDynamic obj) => Convert.ToInt64(obj.SimpleValue);
public static explicit operator ulong(ClrDynamic obj) => Convert.ToUInt64(obj.SimpleValue);
public static explicit operator float(ClrDynamic obj) => Convert.ToSingle(obj.SimpleValue);
public static explicit operator double(ClrDynamic obj) => Convert.ToDouble(obj.SimpleValue);
public static explicit operator DateTime(ClrDynamic obj) => Convert.ToDateTime(obj.SimpleValue);
public static explicit operator decimal(ClrDynamic obj) => Convert.ToDecimal(obj.SimpleValue);
public static explicit operator TimeSpan(ClrDynamic obj) => (TimeSpan)obj.SimpleValue;
public static explicit operator ClrDynamic(ClrObject obj) => new ClrDynamic(obj);

public static explicit operator string(ClrDynamic obj)
{
if (obj.Type.IsEnum)
return obj.Type.GetEnumName(obj.SimpleValue);

return (string)obj.SimpleValue;
return obj.Type.IsEnum
? obj.Type.GetEnumName(obj.SimpleValue)
: Convert.ToString(obj.SimpleValue);
}

public static explicit operator Guid(ClrDynamic obj)
{
return (Guid)obj.SimpleValue;
}

public static explicit operator TimeSpan(ClrDynamic obj)
{
return (TimeSpan)obj.SimpleValue;
}

public static explicit operator DateTime(ClrDynamic obj)
{
return (DateTime)obj.SimpleValue;
if (obj.SimpleValue is Guid g)
return g;
return new Guid((string)obj);
}

public static explicit operator IPAddress(ClrDynamic obj)
{
return (IPAddress)obj.SimpleValue;
}

public static explicit operator ClrDynamic(ClrObject obj)
{
return new ClrDynamic(obj);
if (obj.SimpleValue is IPAddress ip)
return ip;
return IPAddress.Parse((string)obj);
}
#endregion

#endregion

Expand Down Expand Up @@ -583,7 +522,7 @@ private string GetAddressString()
{
if (Address == NullAddress)
return "{null}";

return "0x" + Address.ToString("X");
}

Expand Down Expand Up @@ -635,6 +574,32 @@ private void ToDetailedString(StringBuilder builder, string indentation, bool in

#endregion

#region IConvertible (for System.Convert methods)

TypeCode IConvertible.GetTypeCode() => Type.GetTypeCode();
bool IConvertible.ToBoolean(IFormatProvider provider) => (bool)this;
byte IConvertible.ToByte(IFormatProvider provider) => (byte)this;
char IConvertible.ToChar(IFormatProvider provider) => (char)this;
DateTime IConvertible.ToDateTime(IFormatProvider provider) => (DateTime)this;
decimal IConvertible.ToDecimal(IFormatProvider provider) => (decimal)this;
double IConvertible.ToDouble(IFormatProvider provider) => (double)this;
short IConvertible.ToInt16(IFormatProvider provider) => (short)this;
int IConvertible.ToInt32(IFormatProvider provider) => (int)this;
long IConvertible.ToInt64(IFormatProvider provider) => (long)this;
sbyte IConvertible.ToSByte(IFormatProvider provider) => (sbyte)this;
float IConvertible.ToSingle(IFormatProvider provider) => (float)this;
string IConvertible.ToString(IFormatProvider provider) => (string)this;
ushort IConvertible.ToUInt16(IFormatProvider provider) => (ushort)this;
uint IConvertible.ToUInt32(IFormatProvider provider) => (uint)this;
ulong IConvertible.ToUInt64(IFormatProvider provider) => (ulong)this;

public object ToType(Type conversionType, IFormatProvider provider)
{
return Convert.ChangeType(SimpleValue, conversionType, provider);
}

#endregion

#region SimpleValueHelper

private static class SimpleValueHelper
Expand Down Expand Up @@ -825,7 +790,7 @@ public IEnumerable<string> GetNames()
yield return "";
yield break;
}

if (Type.IsArray)
{
yield return "[Type]";
Expand Down Expand Up @@ -867,10 +832,10 @@ public IEnumerable<Type> GetTypes()

if (HasSimpleValue)
{
yield return GetSimpleValueType();
yield return GetSimpleValueType();
yield break;
}

if (Type.IsArray)
{
// Type Name
Expand Down Expand Up @@ -935,7 +900,7 @@ public IEnumerable<object> GetValues()
yield return SimpleDisplayValue;
yield break;
}

if (Type.IsArray)
{
yield return m_deobfuscator.OriginalName;
Expand Down Expand Up @@ -981,9 +946,9 @@ private IEnumerable<ClrDynamic> EnumerateArray()
private Type GetSimpleValueType()
{
if (SimpleValue == null)
return typeof (object);
return typeof(object);
if (Type.IsEnum)
return typeof (string);
return typeof(string);
return SimpleValue.GetType();
}

Expand Down
61 changes: 61 additions & 0 deletions ClrMD.Extensions/Core/ClrTypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Diagnostics.Runtime;

namespace ClrMD.Extensions.Core
{
public static class ClrTypeExtensions
{
private static readonly Dictionary<string, Type> s_dumpToClrTypes;

static ClrTypeExtensions()
{
s_dumpToClrTypes = new Dictionary<string, Type>();

void AddType(Type t)
{
s_dumpToClrTypes.Add(t.FullName, t);
}

AddType(typeof(object));
AddType(typeof(string));
AddType(typeof(void));
AddType(typeof(byte));
AddType(typeof(sbyte));
AddType(typeof(short));
AddType(typeof(ushort));
AddType(typeof(int));
AddType(typeof(uint));
AddType(typeof(long));
AddType(typeof(ulong));
AddType(typeof(float));
AddType(typeof(double));
AddType(typeof(decimal));
AddType(typeof(Guid));
AddType(typeof(DateTime));
AddType(typeof(TimeSpan));
AddType(typeof(IPAddress));
AddType(typeof(IPEndPoint));
AddType(typeof(DnsEndPoint));
AddType(typeof(X509Certificate));
AddType(typeof(X509Certificate2));
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IPEndPoint/DnsEndPoint/X509Certificate/X509Certificate2 should not be there


public static Type GetRealType(this ClrType type)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this method needs to exist

{
if (s_dumpToClrTypes.TryGetValue(type.Name, out var t))
return t;

throw new ArgumentException("Only basic types can be matched to the concrete runtime types");
}

public static TypeCode GetTypeCode(this ClrType type)
{
return s_dumpToClrTypes.TryGetValue(type.Name, out var t)
? Type.GetTypeCode(t)
: TypeCode.Object;
}
}
}