Several small changes
- Tidy-up value-type methods - Improved enums - Support default interface methods - Re-added executable directory as a search directory
This commit is contained in:
parent
4954a89084
commit
9181b2ab62
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.obj/
|
||||
.vs/
|
||||
packages/
|
||||
/TODO
|
||||
|
@ -182,7 +182,7 @@ namespace system
|
||||
{
|
||||
srcObj = (ValueType) java.lang.reflect.Array.get(srcArr, sourceIndex + length);
|
||||
dstObj = (ValueType) java.lang.reflect.Array.get(dstArr, destinationIndex + length);
|
||||
((ValueMethod) ((ValueType) srcObj)).CopyInto((ValueType) dstObj);
|
||||
((ValueMethod) ((ValueType) srcObj)).CopyTo((ValueType) dstObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -191,7 +191,7 @@ namespace system
|
||||
{
|
||||
srcObj = (ValueType) java.lang.reflect.Array.get(srcArr, sourceIndex + idx);
|
||||
dstObj = (ValueType) java.lang.reflect.Array.get(dstArr, destinationIndex + idx);
|
||||
((ValueMethod) ((ValueType) srcObj)).CopyInto((ValueType) dstObj);
|
||||
((ValueMethod) ((ValueType) srcObj)).CopyTo((ValueType) dstObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1028,7 +1028,7 @@ namespace system
|
||||
// this will throw invalid cast if the types do not match.
|
||||
// but note that it will succeed with generic instance types
|
||||
// even when the type arguments do not match.
|
||||
((ValueMethod) ((ValueType) valueArray[index])).CopyInto((ValueType) value);
|
||||
((ValueMethod) ((ValueType) valueArray[index])).CopyTo((ValueType) value);
|
||||
break;
|
||||
|
||||
case object[] objectArray:
|
||||
|
@ -38,8 +38,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Boolean) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Boolean) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Boolean) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -51,8 +51,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((SByte) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((SByte) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((SByte) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -56,8 +56,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Char) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Char) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Char) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -59,8 +59,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Double) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Double) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Double) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -5,109 +5,68 @@ namespace system
|
||||
interface EnumFlags { }
|
||||
|
||||
[System.Serializable]
|
||||
public abstract class Enum : system.ValueType, system.ValueMethod, System.IComparable
|
||||
//System.IFormattable, System.IConvertible
|
||||
public abstract class Enum : system.ValueType, system.ValueMethod, System.IComparable,
|
||||
System.IFormattable //System.IConvertible
|
||||
{
|
||||
|
||||
public static object Box(int v, java.lang.Class cls)
|
||||
{
|
||||
var obj = (system.Enum) cls.newInstance();
|
||||
Enum.Set(v, obj, cls);
|
||||
return obj;
|
||||
}
|
||||
//
|
||||
// getters and setters
|
||||
//
|
||||
|
||||
[System.Runtime.CompilerServices.SpecialName] // discard "Long" in name; see CilMethod
|
||||
public abstract long GetLong();
|
||||
|
||||
[System.Runtime.CompilerServices.SpecialName] // discard "Long" in name; see CilMethod
|
||||
public abstract void SetLong(long v);
|
||||
|
||||
public virtual int Get() => (int) GetLong();
|
||||
public virtual void Set(int v) => SetLong((long) v);
|
||||
public static void Set(int v, Enum e) => e.SetLong((long) v);
|
||||
public static void Set(long v, Enum e) => e.SetLong(v);
|
||||
|
||||
public virtual int VolatileGet() => throw new System.NotSupportedException();
|
||||
public virtual void VolatileSet(int v) => throw new System.NotSupportedException();
|
||||
public virtual void VolatileSet(long v) => throw new System.NotSupportedException();
|
||||
public static void VolatileSet(int v, Enum e) => throw new System.NotSupportedException();
|
||||
public static void VolatileSet(long v, Enum e) => throw new System.NotSupportedException();
|
||||
|
||||
|
||||
public static object Box(long v, java.lang.Class cls)
|
||||
{
|
||||
var obj = cls.newInstance();
|
||||
Util.GetEnumField(cls).setLong(obj, v);
|
||||
var constructor = cls.getConstructor(null);
|
||||
constructor.setAccessible(true);
|
||||
var obj = (system.Enum) constructor.newInstance(null);
|
||||
obj.SetLong(v);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public virtual int Get() =>
|
||||
Util.GetEnumField(((java.lang.Object) (object) this).getClass()).getInt(this);
|
||||
|
||||
[System.Runtime.CompilerServices.SpecialName] // discard "Long" in name; see CilMethod
|
||||
public virtual long GetLong() =>
|
||||
Util.GetEnumField(((java.lang.Object) (object) this).getClass()).getLong(this);
|
||||
|
||||
public virtual int VolatileGet() => throw new System.NotSupportedException();
|
||||
|
||||
[System.Runtime.CompilerServices.SpecialName] // discard "Long" in name; see CilMethod
|
||||
public virtual long VolatileGetLong() => throw new System.NotSupportedException();
|
||||
|
||||
public virtual void Set(int v) => Set(v, this);
|
||||
public virtual void VolatileSet(int v) => throw new System.NotSupportedException();
|
||||
|
||||
public virtual void Set(long v) => Set(v, this);
|
||||
public virtual void VolatileSet(long v) => throw new System.NotSupportedException();
|
||||
|
||||
public static void Set(int v, Int32 o) => o.Set(v);
|
||||
public static void VolatileSet(int v, Int32 o) => o.VolatileSet(v);
|
||||
public static object Box(int v, java.lang.Class cls) => Box((long) v, cls);
|
||||
|
||||
|
||||
|
||||
public static void Set(int v, system.Enum obj)
|
||||
=> Set(v, obj, ((java.lang.Object) (object) obj).getClass());
|
||||
|
||||
public static void Set(long v, system.Enum obj)
|
||||
=> Set(v, obj, ((java.lang.Object) (object) obj).getClass());
|
||||
|
||||
|
||||
|
||||
public static void Set(int v, system.Enum obj, java.lang.Class cls)
|
||||
public int CompareTo(object other)
|
||||
{
|
||||
var fld = Util.GetEnumField(cls);
|
||||
cls = fld.getType();
|
||||
|
||||
if (cls == java.lang.Integer.TYPE)
|
||||
fld.setInt(obj, v);
|
||||
else if (cls == java.lang.Short.TYPE)
|
||||
fld.setShort(obj, (short) v);
|
||||
else if (cls == java.lang.Byte.TYPE)
|
||||
fld.setByte(obj, (sbyte) v);
|
||||
else
|
||||
fld.setLong(obj, (long) v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void Set(long v, system.Enum obj, java.lang.Class cls)
|
||||
{
|
||||
Util.GetEnumField(cls).setLong(obj, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
if (other == null)
|
||||
return (this != null) ? 1 : 0;
|
||||
|
||||
var cls = ((java.lang.Object) (object) this).getClass();
|
||||
if (cls != ((java.lang.Object) obj).getClass())
|
||||
if (cls != ((java.lang.Object) other).getClass())
|
||||
throw new System.ArgumentException();
|
||||
|
||||
var fld = Util.GetEnumField(cls);
|
||||
var v1 = fld.getLong(this);
|
||||
var v2 = fld.getLong(obj);
|
||||
return java.lang.Long.signum(v1 - v2);
|
||||
return java.lang.Long.signum(
|
||||
GetLong() - ((Enum) other).GetLong());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (obj != null)
|
||||
if (other != null)
|
||||
{
|
||||
var cls = ((java.lang.Object) (object) this).getClass();
|
||||
if (cls == ((java.lang.Object) obj).getClass())
|
||||
if (cls == ((java.lang.Object) other).getClass())
|
||||
{
|
||||
var fld = Util.GetEnumField(cls);
|
||||
var v1 = fld.getLong(this);
|
||||
var v2 = fld.getLong(obj);
|
||||
if (v1 == v2)
|
||||
if (GetLong() == ((Enum) other).GetLong())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -116,138 +75,191 @@ namespace system
|
||||
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
public override int GetHashCode() => java.lang.Long.hashCode(GetLong());
|
||||
|
||||
|
||||
|
||||
//
|
||||
// GetUnderlyingType
|
||||
//
|
||||
|
||||
public static System.Type GetUnderlyingType(System.Type enumType)
|
||||
{
|
||||
var cls = ((java.lang.Object) (object) this).getClass();
|
||||
return java.lang.Long.hashCode(Util.GetEnumField(cls).getLong(this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var cls = ((java.lang.Object) (object) this).getClass();
|
||||
var fld = Util.GetEnumField(cls);
|
||||
if (fld != null)
|
||||
{
|
||||
var v = fld.getLong(this);
|
||||
string s;
|
||||
|
||||
var flds = cls.getDeclaredFields();
|
||||
int n = flds.Length;
|
||||
|
||||
if (this is EnumFlags)
|
||||
s = Util.EnumToStringMulti(v, flds, n);
|
||||
else
|
||||
s = Util.EnumToStringSingle(v, flds, n);
|
||||
|
||||
return s ?? java.lang.Long.toString(v);
|
||||
}
|
||||
Util.BadEnum(cls);
|
||||
return default(string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Enum) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Enum) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => (ValueType) Box(Get(), ((java.lang.Object) (object) this).getClass());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Enum Util
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public static partial class Util
|
||||
{
|
||||
|
||||
[java.attr.RetainType] private static java.util.concurrent.ConcurrentHashMap enumMap =
|
||||
new java.util.concurrent.ConcurrentHashMap();
|
||||
|
||||
|
||||
|
||||
internal static void BadEnum(java.lang.Class cls)
|
||||
{
|
||||
throw new System.ArgumentException("Bad enum " + cls);
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static java.lang.reflect.Field GetEnumField(java.lang.Class cls)
|
||||
{
|
||||
var field = enumMap.get(cls);
|
||||
if (field != null)
|
||||
return (java.lang.reflect.Field) field;
|
||||
|
||||
foreach (var f in cls.getDeclaredFields())
|
||||
{
|
||||
if (f.getModifiers() == java.lang.reflect.Modifier.PUBLIC)
|
||||
{
|
||||
enumMap.put(cls, f);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
BadEnum(cls);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static string EnumToStringSingle(long v, java.lang.reflect.Field[] fields, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var f = fields[i];
|
||||
if (f.getModifiers() == ( java.lang.reflect.Modifier.PUBLIC
|
||||
| java.lang.reflect.Modifier.STATIC))
|
||||
{
|
||||
if (f.getLong(null) == v)
|
||||
return f.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static string EnumToStringMulti(long v, java.lang.reflect.Field[] fields, int n)
|
||||
{
|
||||
return "???";
|
||||
ThrowHelper.ThrowIfNull(enumType);
|
||||
return enumType.GetEnumUnderlyingType();
|
||||
#if false
|
||||
var sb = new java.lang.StringBuilder();
|
||||
bool comma = false;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
if (enumType.IsEnum && enumType is RuntimeType enumRuntimeType)
|
||||
{
|
||||
var f = fields[i];
|
||||
if (f.getModifiers() == ( java.lang.reflect.Modifier.PUBLIC
|
||||
| java.lang.reflect.Modifier.STATIC))
|
||||
var fields = enumRuntimeType.JavaClassForArray().getDeclaredFields();
|
||||
if (fields.Length > 1)
|
||||
{
|
||||
var fv = f.getLong(null);
|
||||
if ((fv & v) == fv)
|
||||
var f = fields[0];
|
||||
if ((f.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0)
|
||||
{
|
||||
v &= ~fv;
|
||||
if (comma)
|
||||
sb.append(", ");
|
||||
sb.append(f.getName());
|
||||
comma = true;
|
||||
var fldType = system.RuntimeType.GetType(f.getType());
|
||||
var typeCode = (int) System.Type.GetTypeCode(fldType);
|
||||
if (typeCode >= 4 && typeCode <= 12)
|
||||
return fldType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (v == 0) ? sb.ToString() : null;
|
||||
throw new System.ArgumentException();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// ToString and Format
|
||||
//
|
||||
|
||||
public override string ToString() => ToString((string) null);
|
||||
|
||||
public string ToString(System.IFormatProvider provider)
|
||||
=> ToString((string) null);
|
||||
|
||||
public string ToString(string format, System.IFormatProvider formatProvider)
|
||||
=> ToString(format);
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
if (format == null || format.Length == 0)
|
||||
format = "G";
|
||||
return Format(format, GetLong(), ((java.lang.Object) (object) this).getClass());
|
||||
}
|
||||
|
||||
public static string Format(System.Type enumType, object value, string format)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(enumType);
|
||||
if (! enumType.IsEnum)
|
||||
throw new System.ArgumentException();
|
||||
ThrowHelper.ThrowIfNull(value, format);
|
||||
|
||||
if (enumType is RuntimeType enumRuntimeType)
|
||||
{
|
||||
var enumUnderlyingType = GetUnderlyingType(enumType);
|
||||
var enumCls = enumRuntimeType.JavaClassForArray();
|
||||
var valueType = value.GetType();
|
||||
|
||||
if (value is Enum valueEnum)
|
||||
{
|
||||
var valueUnderlyingType = GetUnderlyingType(valueType);
|
||||
if (object.ReferenceEquals(enumUnderlyingType, valueUnderlyingType))
|
||||
return Format(format, valueEnum.GetLong(), enumCls);
|
||||
}
|
||||
else if (object.ReferenceEquals(enumUnderlyingType, valueType))
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case byte byteValue: return Format(format, (long) byteValue, enumCls);
|
||||
case char charValue: return Format(format, (long) charValue, enumCls);
|
||||
case short shortValue: return Format(format, (long) shortValue, enumCls);
|
||||
case int intValue: return Format(format, (long) intValue, enumCls);
|
||||
case long longValue: return Format(format, longValue, enumCls);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new System.ArgumentException();
|
||||
}
|
||||
|
||||
private static string Format(string format, long value, java.lang.Class cls)
|
||||
{
|
||||
if (format.Length == 1)
|
||||
{
|
||||
bool asFlags = false;
|
||||
switch (format[0])
|
||||
{
|
||||
case 'f': case 'F':
|
||||
asFlags = true;
|
||||
goto case 'G';
|
||||
|
||||
case 'g': case 'G':
|
||||
if (! asFlags)
|
||||
{
|
||||
asFlags = ((java.lang.Class) typeof (EnumFlags))
|
||||
.isAssignableFrom(cls);
|
||||
}
|
||||
return FormatNames(cls, asFlags, value);
|
||||
|
||||
case 'd': case 'D':
|
||||
return java.lang.Long.toString(value);
|
||||
|
||||
case 'x': case 'X':
|
||||
return java.lang.Long.toHexString(value);
|
||||
}
|
||||
}
|
||||
throw new System.FormatException();
|
||||
|
||||
|
||||
|
||||
static string FormatNames(java.lang.Class cls, bool asFlags, long v)
|
||||
{
|
||||
var fields = cls.getDeclaredFields();
|
||||
int n = fields.Length;
|
||||
|
||||
var s = asFlags
|
||||
? ToStringMulti(v, fields, n)
|
||||
: ToStringSingle(v, fields, n);
|
||||
return s ?? java.lang.Long.toString(v);
|
||||
}
|
||||
|
||||
static string ToStringSingle(long v, java.lang.reflect.Field[] fields, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var f = fields[i];
|
||||
if (f.getModifiers() == ( java.lang.reflect.Modifier.PUBLIC
|
||||
| java.lang.reflect.Modifier.STATIC))
|
||||
{
|
||||
f.setAccessible(true);
|
||||
if (f.getLong(null) == v)
|
||||
return f.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static string ToStringMulti(long v, java.lang.reflect.Field[] fields, int n)
|
||||
{
|
||||
var v0 = v;
|
||||
var sb = new java.lang.StringBuilder();
|
||||
bool comma = false;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
var f = fields[i];
|
||||
if (f.getModifiers() == ( java.lang.reflect.Modifier.PUBLIC
|
||||
| java.lang.reflect.Modifier.STATIC))
|
||||
{
|
||||
f.setAccessible(true);
|
||||
var fv = f.getLong(null);
|
||||
|
||||
if ((fv & v) == fv)
|
||||
{
|
||||
if (fv == 0 && v0 != 0)
|
||||
{
|
||||
// skip field for zero, if value was not zero
|
||||
continue;
|
||||
}
|
||||
v &= ~fv;
|
||||
if (comma)
|
||||
sb.append(", ");
|
||||
sb.append(f.getName());
|
||||
comma = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (v == 0) ? sb.ToString() : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ValueMethod.Clear() => SetLong(0L);
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Enum) into).SetLong(GetLong());
|
||||
ValueType ValueMethod.Clone() => (ValueType) this.MemberwiseClone();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace system
|
||||
}
|
||||
else if (fromObj is ValueType fromValue)
|
||||
{
|
||||
((ValueMethod) fromValue).CopyInto((ValueType) toObj);
|
||||
((ValueMethod) fromValue).CopyTo((ValueType) toObj);
|
||||
}
|
||||
else if (fromObj is java.lang.Comparable)
|
||||
{
|
||||
|
@ -53,8 +53,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Int16) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Int16) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Int16) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -87,8 +87,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Int32) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Int32) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Int32) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -77,8 +77,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Int64) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Int64) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Int64) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -47,8 +47,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(null);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Reference) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Reference) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Reference) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
139
Baselib/src/System/Reflection/BindingFlagsIterator.cs
Normal file
139
Baselib/src/System/Reflection/BindingFlagsIterator.cs
Normal file
@ -0,0 +1,139 @@
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace system.reflection
|
||||
{
|
||||
|
||||
public sealed class BindingFlagsIterator
|
||||
{
|
||||
|
||||
// entrypoint
|
||||
|
||||
public static void Run(BindingFlags bindingAttr,
|
||||
RuntimeType initialType,
|
||||
MemberTypes memberType,
|
||||
System.Predicate<java.lang.reflect.AccessibleObject> callback)
|
||||
{
|
||||
int modifierMask = 0;
|
||||
int modifierValue = 0;
|
||||
|
||||
BindingFlags chk = bindingAttr & (BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (chk != (BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (chk == 0) // if neither, no methods will match
|
||||
return;
|
||||
// methods with internal access are converted to public access,
|
||||
// so we cannot honor the distinction between Public and NonPublic
|
||||
/*
|
||||
modifierMask |= java.lang.reflect.Modifier.PUBLIC;
|
||||
if (chk == BindingFlags.Public)
|
||||
modifierValue |= java.lang.reflect.Modifier.PUBLIC;
|
||||
*/
|
||||
}
|
||||
bindingAttr &= ~chk;
|
||||
|
||||
chk = bindingAttr & (BindingFlags.Static | BindingFlags.Instance);
|
||||
if (chk != (BindingFlags.Static | BindingFlags.Instance))
|
||||
{
|
||||
if (chk == 0) // if neither, no methods will match
|
||||
return;
|
||||
modifierMask |= java.lang.reflect.Modifier.STATIC;
|
||||
if (chk == BindingFlags.Static)
|
||||
modifierValue |= java.lang.reflect.Modifier.STATIC;
|
||||
}
|
||||
bindingAttr &= ~chk;
|
||||
|
||||
RuntimeType stopAtType = null;
|
||||
if ((bindingAttr & BindingFlags.DeclaredOnly) != 0)
|
||||
{
|
||||
stopAtType = initialType;
|
||||
bindingAttr &= ~BindingFlags.DeclaredOnly;
|
||||
}
|
||||
|
||||
if (bindingAttr != 0)
|
||||
{
|
||||
throw new System.PlatformNotSupportedException(
|
||||
"bad binding flags " + bindingAttr);
|
||||
}
|
||||
|
||||
switch (memberType)
|
||||
{
|
||||
case MemberTypes.Method:
|
||||
RunMethods(modifierMask, modifierValue, initialType, stopAtType, callback);
|
||||
return;
|
||||
|
||||
case MemberTypes.Field:
|
||||
RunFields(modifierMask, modifierValue, initialType, stopAtType, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new System.ArgumentException();
|
||||
}
|
||||
|
||||
//
|
||||
// method iterator
|
||||
//
|
||||
|
||||
static void RunMethods(int modifierMask, int modifierValue,
|
||||
RuntimeType initialType, RuntimeType stopAtType,
|
||||
System.Predicate<java.lang.reflect.AccessibleObject> callback)
|
||||
{
|
||||
var currentType = initialType;
|
||||
for (;;)
|
||||
{
|
||||
#pragma warning disable 0436
|
||||
java.lang.reflect.Method[] javaMethods =
|
||||
(java.lang.reflect.Method[]) (object)
|
||||
currentType.JavaClassForArray().getDeclaredMethods();
|
||||
#pragma warning restore 0436
|
||||
|
||||
foreach (var javaMethod in javaMethods)
|
||||
{
|
||||
int jmodifiers = javaMethod.getModifiers();
|
||||
if ((jmodifiers & modifierMask) == modifierValue)
|
||||
{
|
||||
if (! callback(javaMethod))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentType = (system.RuntimeType) currentType.BaseType;
|
||||
if (currentType == stopAtType)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// field iterator
|
||||
//
|
||||
|
||||
static void RunFields(int modifierMask, int modifierValue,
|
||||
RuntimeType initialType, RuntimeType stopAtType,
|
||||
System.Predicate<java.lang.reflect.AccessibleObject> callback)
|
||||
{
|
||||
var currentType = initialType;
|
||||
for (;;)
|
||||
{
|
||||
java.lang.reflect.Field[] javaFields =
|
||||
(java.lang.reflect.Field[]) (object)
|
||||
currentType.JavaClassForArray().getDeclaredFields();
|
||||
|
||||
foreach (var javaField in javaFields)
|
||||
{
|
||||
int jmodifiers = javaField.getModifiers();
|
||||
if ((jmodifiers & modifierMask) == modifierValue)
|
||||
{
|
||||
if (! callback(javaField))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentType = (system.RuntimeType) currentType.BaseType;
|
||||
if (currentType == stopAtType)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
97
Baselib/src/System/Reflection/RuntimeFieldInfo.cs
Normal file
97
Baselib/src/System/Reflection/RuntimeFieldInfo.cs
Normal file
@ -0,0 +1,97 @@
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace system.reflection
|
||||
{
|
||||
|
||||
[System.Serializable]
|
||||
public sealed class RuntimeFieldInfo : FieldInfo, ISerializable
|
||||
{
|
||||
[java.attr.RetainType] public java.lang.reflect.Field JavaField;
|
||||
[java.attr.RetainType] public system.RuntimeType reflectedType;
|
||||
|
||||
//
|
||||
// constructor
|
||||
//
|
||||
|
||||
private RuntimeFieldInfo(java.lang.reflect.Field javaField,
|
||||
system.RuntimeType reflectedType)
|
||||
{
|
||||
this.JavaField = javaField;
|
||||
this.reflectedType = reflectedType;
|
||||
}
|
||||
|
||||
//
|
||||
// GetFields (called by system.RuntimeType.GetFields(GetFields)
|
||||
//
|
||||
|
||||
public static FieldInfo[] GetFields(BindingFlags bindingAttr, RuntimeType initialType)
|
||||
{
|
||||
var list = new System.Collections.Generic.List<FieldInfo>();
|
||||
|
||||
BindingFlagsIterator.Run(bindingAttr, initialType, MemberTypes.Field,
|
||||
(javaAccessibleObject) =>
|
||||
{
|
||||
list.Add(new RuntimeFieldInfo((java.lang.reflect.Field) javaAccessibleObject,
|
||||
initialType));
|
||||
return true;
|
||||
});
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public override System.Type FieldType
|
||||
=> system.RuntimeType.GetType(JavaField.getType());
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
public override object GetValue(object obj)
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override void SetValue(object obj, object value, BindingFlags invokeAttr,
|
||||
Binder binder, CultureInfo culture)
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override System.Reflection.FieldAttributes Attributes
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override System.Type DeclaringType
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override System.Type ReflectedType
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override string Name
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override System.RuntimeFieldHandle FieldHandle
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
//
|
||||
// custom attributes
|
||||
//
|
||||
|
||||
public override bool IsDefined(Type attributeType, bool inherit)
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override object[] GetCustomAttributes(bool inherit)
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
//
|
||||
// ISerializable
|
||||
//
|
||||
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -356,7 +356,7 @@ namespace system.reflection
|
||||
|
||||
public override string Name => strippedName;
|
||||
|
||||
public override RuntimeMethodHandle MethodHandle
|
||||
public override System.RuntimeMethodHandle MethodHandle
|
||||
=> throw new PlatformNotSupportedException();
|
||||
|
||||
public override ParameterInfo[] GetParameters()
|
||||
|
15
Baselib/src/System/RuntimeHandles.cs
Normal file
15
Baselib/src/System/RuntimeHandles.cs
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
namespace system
|
||||
{
|
||||
|
||||
[System.Serializable]
|
||||
public struct RuntimeFieldHandle
|
||||
{
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct RuntimeMethodHandle
|
||||
{
|
||||
}
|
||||
|
||||
}
|
@ -1488,7 +1488,7 @@ namespace system
|
||||
|
||||
public override FieldInfo[] GetFields(BindingFlags bindingAttr)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
return system.reflection.RuntimeFieldInfo.GetFields(bindingAttr, this);
|
||||
}
|
||||
|
||||
public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
|
||||
@ -1532,7 +1532,6 @@ namespace system
|
||||
public virtual Type[] GetGenericParameterConstraints()
|
||||
|
||||
public virtual Array GetEnumValues()
|
||||
public virtual Type GetEnumUnderlyingType()
|
||||
|
||||
internal virtual string FormatTypeName(bool serialization)
|
||||
public virtual InterfaceMapping GetInterfaceMap(Type interfaceType)
|
||||
@ -1564,6 +1563,7 @@ namespace system
|
||||
public virtual bool IsInstanceOfType(Object o)
|
||||
public virtual bool IsEquivalentTo(Type other)
|
||||
|
||||
public virtual Type GetEnumUnderlyingType()
|
||||
public virtual string[] GetEnumNames()
|
||||
public virtual bool IsEnumDefined(object value)
|
||||
public virtual string GetEnumName(object value)
|
||||
|
@ -59,8 +59,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() => Set(0);
|
||||
void ValueMethod.CopyFrom(ValueType from) => Set(((Single) from).Get());
|
||||
void ValueMethod.CopyInto(ValueType into) => ((Single) into).Set(Get());
|
||||
void ValueMethod.CopyTo(ValueType into) => ((Single) into).Set(Get());
|
||||
ValueType ValueMethod.Clone() => Box(Get());
|
||||
|
||||
|
||||
|
@ -52,7 +52,6 @@ namespace system
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
|
||||
var fields = ((java.lang.Object) (object) this).getClass().getDeclaredFields();
|
||||
int numFields = fields.Length;
|
||||
|
||||
@ -78,8 +77,7 @@ namespace system
|
||||
|
||||
|
||||
void ValueMethod.Clear() {}
|
||||
void ValueMethod.CopyFrom(ValueType from) {}
|
||||
void ValueMethod.CopyInto(ValueType into) {}
|
||||
void ValueMethod.CopyTo(ValueType other) {}
|
||||
ValueType ValueMethod.Clone() => null;
|
||||
}
|
||||
|
||||
@ -89,8 +87,7 @@ namespace system
|
||||
interface ValueMethod
|
||||
{
|
||||
void Clear();
|
||||
void CopyFrom(ValueType from);
|
||||
void CopyInto(ValueType into);
|
||||
void CopyTo(ValueType other);
|
||||
ValueType Clone();
|
||||
}
|
||||
|
||||
|
@ -331,6 +331,13 @@ namespace SpaceFlint.CilToJava
|
||||
if ( (fromMethod.IsPublic || fromMethod.HasOverrides)
|
||||
&& ! (fromMethod.IsStatic || fromMethod.IsConstructor))
|
||||
{
|
||||
if (fromType.IsInterface && fromMethod.HasBody)
|
||||
{
|
||||
// skip default interface methods, they are not needed
|
||||
// in the context of resolving interface implementations
|
||||
continue;
|
||||
}
|
||||
|
||||
var genericMark = CilMain.GenericStack.Mark();
|
||||
var inputMethod = CilMain.GenericStack.EnterMethod(fromMethod);
|
||||
|
||||
|
@ -831,12 +831,8 @@ namespace SpaceFlint.CilToJava
|
||||
internal static readonly JavaMethodRef ValueClear =
|
||||
new JavaMethod("system-ValueMethod-Clear", JavaType.VoidType);
|
||||
|
||||
internal static readonly JavaMethodRef ValueCopyFrom =
|
||||
new JavaMethod("system-ValueMethod-CopyFrom",
|
||||
JavaType.VoidType, CilType.SystemValueType);
|
||||
|
||||
internal static readonly JavaMethodRef ValueCopyInto =
|
||||
new JavaMethod("system-ValueMethod-CopyInto",
|
||||
internal static readonly JavaMethodRef ValueCopyTo =
|
||||
new JavaMethod("system-ValueMethod-CopyTo",
|
||||
JavaType.VoidType, CilType.SystemValueType);
|
||||
|
||||
internal static readonly JavaMethodRef ValueClone =
|
||||
|
@ -179,6 +179,14 @@ namespace SpaceFlint.CilToJava
|
||||
Flags &= ~VALUE;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
if (fromType.Name == "RuntimeFieldHandle")
|
||||
{
|
||||
CopyFrom(ReflectFieldType);
|
||||
JavaName = ClassName;
|
||||
Flags &= ~VALUE;
|
||||
return;
|
||||
}
|
||||
if (fromType.Name == "RuntimeMethodHandle")
|
||||
{
|
||||
CopyFrom(ReflectMethodType);
|
||||
@ -186,6 +194,7 @@ namespace SpaceFlint.CilToJava
|
||||
Flags &= ~VALUE;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -659,6 +668,8 @@ namespace SpaceFlint.CilToJava
|
||||
internal static readonly JavaType SystemUtilType = new JavaType(0, 0, "system.Util");
|
||||
internal static readonly JavaType SystemValueType = new JavaType(0, 0, "system.ValueType");
|
||||
|
||||
/*internal static readonly CilType ReflectFieldType =
|
||||
CilType.From(new JavaType(0, 0, "java.lang.reflect.Field"));*/
|
||||
internal static readonly CilType ReflectMethodType =
|
||||
CilType.From(new JavaType(0, 0, "java.lang.reflect.Method"));
|
||||
}
|
||||
|
@ -347,7 +347,8 @@ namespace SpaceFlint.CilToJava
|
||||
code.NewInstruction(elemType.LoadOpcode, null, localIndex);
|
||||
locals.FreeTempIndex(localIndex);
|
||||
|
||||
CilMethod.ValueMethod(CilMethod.ValueCopyFrom, code);
|
||||
// we can pass any type that is not a generic parameter
|
||||
GenericUtil.ValueCopy(CilType.SystemTypeType, code, true);
|
||||
}
|
||||
else if (arrayType.ArrayRank > 1)
|
||||
{
|
||||
|
@ -406,6 +406,26 @@ namespace SpaceFlint.CilToJava
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( callClass.JavaName == null
|
||||
&& callClass.Equals(JavaType.ClassType)
|
||||
&& callMethod.Name == "GetRuntimeType")
|
||||
{
|
||||
// convert virtual call to RuntimeTypeHandle.GetRuntimeType
|
||||
// to a static call to system.RuntimeType
|
||||
|
||||
code.NewInstruction(0xB8 /* invokestatic */,
|
||||
CilType.SystemRuntimeTypeType,
|
||||
new JavaMethodRef(
|
||||
callMethod.Name, callMethod.ReturnType,
|
||||
JavaType.ObjectType));
|
||||
|
||||
ClearMethodArguments(callMethod, false);
|
||||
PushMethodReturnType(callMethod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -330,8 +330,10 @@ namespace SpaceFlint.CilToJava
|
||||
if (boxedType != null)
|
||||
{
|
||||
boxedType.BoxValue(code);
|
||||
#if false
|
||||
if (plainType.IsEnum)
|
||||
code.NewInstruction(0xC0 /* checkcast */, boxedType, null);
|
||||
#endif
|
||||
}
|
||||
else if (plainType.IsGenericParameter)
|
||||
{
|
||||
|
@ -704,8 +704,9 @@ namespace SpaceFlint.CilToJava
|
||||
}
|
||||
else
|
||||
{
|
||||
var method = swap ? CilMethod.ValueCopyFrom : CilMethod.ValueCopyInto;
|
||||
CilMethod.ValueMethod(method, code);
|
||||
if (swap)
|
||||
code.NewInstruction(0x5F /* swap */, null, null);
|
||||
CilMethod.ValueMethod(CilMethod.ValueCopyTo, code);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ namespace SpaceFlint.CilToJava
|
||||
else if (myType.IsEnum)
|
||||
{
|
||||
ValueUtil.MakeEnumClass(jclass, myType,
|
||||
cilType.HasCustomAttribute("System.FlagsAttribute"));
|
||||
cilType.HasCustomAttribute("System.FlagsAttribute", true));
|
||||
}
|
||||
|
||||
else if (myType.IsDelegate)
|
||||
|
@ -85,8 +85,7 @@ namespace SpaceFlint.CilToJava
|
||||
static void CreateValueMethods(JavaClass valueClass, CilType fromType)
|
||||
{
|
||||
CreateValueClearMethod(valueClass, fromType);
|
||||
CreateValueCopyMethod(valueClass, fromType, CilMethod.ValueCopyFrom, 1, 0);
|
||||
CreateValueCopyMethod(valueClass, fromType, CilMethod.ValueCopyInto, 0, 1);
|
||||
CreateValueCopyToMethod(valueClass, fromType);
|
||||
CreateValueCloneMethod(valueClass, fromType);
|
||||
|
||||
//
|
||||
@ -108,7 +107,8 @@ namespace SpaceFlint.CilToJava
|
||||
{
|
||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
||||
code.NewInstruction(0xB4 /* getfield */, fromType, fld);
|
||||
code.NewInstruction(0xB6 /* invokevirtual */, fldType, CilMethod.ValueClear);
|
||||
code.NewInstruction(0xB6 /* invokevirtual */,
|
||||
fldType, CilMethod.ValueClear);
|
||||
|
||||
}
|
||||
else
|
||||
@ -124,15 +124,14 @@ namespace SpaceFlint.CilToJava
|
||||
}
|
||||
|
||||
//
|
||||
// builds a system-ValueMethod-CopyXxxx() method, which takes a value
|
||||
// builds a system-ValueMethod-CopyTo() method, which takes a value
|
||||
// type object parameter, along with a 'this' object reference, and
|
||||
// copies each field from one object to the other
|
||||
// copies each field from 'this' object to the other object
|
||||
//
|
||||
|
||||
void CreateValueCopyMethod(JavaClass valueClass, CilType fromType,
|
||||
JavaMethodRef model, int localFrom, int localInto)
|
||||
void CreateValueCopyToMethod(JavaClass valueClass, CilType fromType)
|
||||
{
|
||||
var code = CilMain.CreateHelperMethod(valueClass, model, 2, 2);
|
||||
var code = CilMain.CreateHelperMethod(valueClass, CilMethod.ValueCopyTo, 2, 2);
|
||||
bool atLeastOneField = false;
|
||||
|
||||
if (valueClass.Fields != null && valueClass.Fields.Count != 0)
|
||||
@ -157,13 +156,14 @@ namespace SpaceFlint.CilToJava
|
||||
code.NewInstruction(0xB4 /* getfield */, fromType, fld);
|
||||
code.NewInstruction(0x19 /* aload */, null, (int) 1);
|
||||
code.NewInstruction(0xB4 /* getfield */, fromType, fld);
|
||||
code.NewInstruction(0xB6 /* invokevirtual */, fldType, model);
|
||||
code.NewInstruction(0xB6 /* invokevirtual */,
|
||||
fldType, CilMethod.ValueCopyTo);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
code.NewInstruction(0x19 /* aload */, null, localInto);
|
||||
code.NewInstruction(0x19 /* aload */, null, localFrom);
|
||||
code.NewInstruction(0x19 /* aload */, null, (int) 1);
|
||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
||||
code.NewInstruction(0xB4 /* getfield */, fromType, fld);
|
||||
code.NewInstruction(0xB5 /* putfield */, fromType, fld);
|
||||
}
|
||||
@ -229,6 +229,31 @@ namespace SpaceFlint.CilToJava
|
||||
|
||||
if (isFlags)
|
||||
enumClass.AddInterface("system.EnumFlags");
|
||||
|
||||
//
|
||||
// create getter and setter
|
||||
//
|
||||
|
||||
var theClass = new JavaType(0, 0, enumClass.Name);
|
||||
var theField = enumClass.Fields[0];
|
||||
|
||||
var code = CilMain.CreateHelperMethod(enumClass,
|
||||
new JavaMethodRef("Get", JavaType.LongType), 1, 2);
|
||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
||||
code.NewInstruction(0xB4 /* getfield */, theClass, theField);
|
||||
if (enumType.Category == 1)
|
||||
code.NewInstruction(0x85 /* i2l */, null, null);
|
||||
code.NewInstruction(code.Method.ReturnType.ReturnOpcode, null, null);
|
||||
|
||||
code = CilMain.CreateHelperMethod(enumClass,
|
||||
new JavaMethodRef("Set", JavaType.VoidType), 3, 3);
|
||||
code.Method.Parameters.Add(new JavaFieldRef("", JavaType.LongType));
|
||||
code.NewInstruction(0x19 /* aload */, null, (int) 0);
|
||||
code.NewInstruction(0x16 /* lload */, null, (int) 1);
|
||||
if (enumType.Category == 1)
|
||||
code.NewInstruction(0x88 /* l2i */, null, null);
|
||||
code.NewInstruction(0xB5 /* putfield */, theClass, theField);
|
||||
code.NewInstruction(code.Method.ReturnType.ReturnOpcode, null, null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -489,9 +489,9 @@ public class CilTool
|
||||
|
||||
AddSearchDirectory(Directory.GetCurrentDirectory());
|
||||
|
||||
/*MainModuleFileName =
|
||||
MainModuleFileName =
|
||||
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
||||
AddSearchDirectory(Path.GetDirectoryName(MainModuleFileName));*/
|
||||
AddSearchDirectory(Path.GetDirectoryName(MainModuleFileName));
|
||||
|
||||
foreach (var dir in Environment.GetEnvironmentVariable("PATH")
|
||||
?.Split(Path.PathSeparator))
|
||||
|
@ -32,6 +32,7 @@ namespace Tests
|
||||
{
|
||||
TestBoxing();
|
||||
TestObject();
|
||||
TestEnum();
|
||||
}
|
||||
|
||||
void TestBoxing()
|
||||
@ -77,5 +78,28 @@ namespace Tests
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Enum
|
||||
//
|
||||
|
||||
[Flags] enum MyEnum : sbyte { None, First = 1, Second = 8, Third = 32 };
|
||||
|
||||
void TestEnum()
|
||||
{
|
||||
var x = MyEnum.First | MyEnum.Second;
|
||||
object y = (object) x;
|
||||
TestEnum2<MyEnum>(ref x);
|
||||
Console.Write("\t");
|
||||
Console.Write(y);
|
||||
Console.Write($"\t{x:F},{x:G},{x:D},{x:X},{x.GetType().GetEnumUnderlyingType()}");
|
||||
Console.WriteLine();
|
||||
|
||||
void TestEnum2<T>(ref T e)
|
||||
{
|
||||
e = (T) (object) MyEnum.Third;
|
||||
Console.Write(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
40
USAGE.md
40
USAGE.md
@ -23,7 +23,7 @@ If `input_file` is a .NET assembly, then the output is a Java archive containing
|
||||
If the output is an existing archive, it will be updated, not overwritten. The output can alternatively be
|
||||
(1) a directory, in which case unzipped classes will be generated in that directory; or (2) a Java `.class` file, if the (possibly filtered) input can translate to a single class.
|
||||
|
||||
If the input assembly references other assemblies, they are searched in (1) the directory containing the input assembly; (2) the current directory; (4) each directory listed in the `PATH` environment variable; (5) the directories within `%PROGRAMFILES%\DotNet\Shared\Microsoft.NETCore.App` (with later .NET Core versions taking precedence over earlier ones).
|
||||
If the input assembly references other assemblies, they are searched in (1) the directory containing the input assembly; (2) the current directory; (3) the directory containing the Bluebonnet executable (for `Javalib.dll`); (4) each directory listed in the `PATH` environment variable; (5) the directories within `%PROGRAMFILES%\DotNet\Shared\Microsoft.NETCore.App` (with later .NET Core versions taking precedence over earlier ones).
|
||||
|
||||
# Java Interoperability
|
||||
|
||||
@ -50,48 +50,48 @@ In this example, `java.lang.Thread.UncaughtExceptionHandler` is the functional i
|
||||
|
||||
Here are some known differences, deficiencies and incompatibilities of the Bluebonnet .NET implementation, compared to a proper .NET implementation, in no particular order.
|
||||
|
||||
- For desktop applications, the Java entry point 'main' (lowercase) must be defined as public static void main(string[] args).
|
||||
- For desktop applications, the Java entry point `main` (lowercase) must be defined as `public static void main(string[] args)`.
|
||||
|
||||
- Namespace names are translated to lowercase package names, as required by Java. Reflection capitalizes the first letter in each namespace component.
|
||||
|
||||
- Value type objects are implemented as normal JVM class objects, and are not copied into the operand stack by value. Instead, a properly translated method duplicates any non-ref value type arguments that it modifies.
|
||||
|
||||
- Delegate Method property is not supported, and throws MemberAccessException.
|
||||
- `Delegate.Method` property is not supported, and throws `MemberAccessException`.
|
||||
|
||||
- Reflection information for generic types depends on the existence of the Signature attribute in java class files.
|
||||
- Reflection information for generic types depends on the existence of the `Signature` attribute in java class files.
|
||||
|
||||
- BeforeFieldInit is not honored; the static initializer for a class will be called at the discretion of the JVM. if it is a generic class, the static initializer is called when the generic type is first referenced.
|
||||
- `BeforeFieldInit` is not honored; the static initializer for a class will be called at the discretion of the JVM. if it is a generic class, the static initializer is called when the generic type is first referenced.
|
||||
|
||||
- The type system is weaker than .NET when it comes to generic types, and in some casts and assignments are permitted between generic objects that differ only in their type arguments.
|
||||
|
||||
- ConditionalWeakTable is an ephemeron table where (possibly indirect) references from values to keys in the same table are treated as weak references. The JVM does not provide such a mechanism.
|
||||
- `ConditionalWeakTable` is an ephemeron table in .NET, where (possibly indirect) references from values to keys in the same table are treated as weak references. The JVM does not provide such a mechanism.
|
||||
|
||||
- Limited pointer indirection is permitted, but pointer arithmetic is prohibited. Stackalloc buffers are permitted, but must be allocated and accessed using the same type, and may only be assigned to a System.Span of the same type.
|
||||
- Limited pointer indirection is permitted, but pointer arithmetic is prohibited. `stackalloc` buffers are permitted, but must be allocated and accessed using the same type, and may only be assigned to a `System.Span` of the same type.
|
||||
|
||||
- Exceptions originating from Java (JVM or library) are translated to equivalent CLR exception types only when caught. Additionally, System.Exception.ToString prints a stack trace, while java.lang.Throwable.toString does not. This means that uncaught exceptions print the stack twice.
|
||||
- Exceptions originating from Java (JVM or library) are translated to equivalent CLR exception types only when caught. Additionally, `System.Exception.ToString` prints a stack trace, while `java.lang.Throwable.toString` does not. This means that uncaught exceptions print the stack twice.
|
||||
|
||||
- Rectangular multidimensional arrays [,] are implemented as jagged arrays [][] i.e., like Java arrays. typeof(int[,]) == typeof(int[][]). GetArrayRank() returns the actual rank; in .NET it returns 1 for jagged arrays. GetElementType() returns the basic element; in .NET it returns an array type for jagged arrays. All arrays implement the generic interfaces; in .NET only single-dimension and jagged arrays.
|
||||
- Rectangular multidimensional arrays [,] are implemented as jagged arrays [][] i.e., like Java arrays. `typeof(int[,]) == typeof(int[][])`. `GetArrayRank()` returns the actual rank; in .NET it returns 1 for jagged arrays. `GetElementType()` returns the basic element; in .NET it returns an array type for jagged arrays. All arrays implement the generic interfaces; in .NET only single-dimension and jagged arrays.
|
||||
|
||||
- Non-zero lower bounds are not supported in System.Array::CreateInstance.
|
||||
- Non-zero lower bounds are not supported in `System.Array.CreateInstance`.
|
||||
|
||||
- Casting an array object to System.Array, or to an interface, will result in a reference to a helper/proxy object which implements this interface. The program can detect that object.ReferenceEquals(proxy, array) is false. The proxy cannot be cast back to the original array.
|
||||
- Casting an array object to `System.Array`, or to an interface, will result in a reference to a helper/proxy object which implements this interface. The program can detect that `object.ReferenceEquals(proxy, array)` is false. The proxy cannot be cast back to the original array.
|
||||
|
||||
- IEnumerable.Current implemented for an array of primitive integers will always return signed objects (System.Int32), never unsigned (System.UInt32).
|
||||
- `IEnumerable.Current` implemented for an array of primitive integers always returns signed objects (e.g `System.Int32`), never unsigned (`System.UInt32`). This does not make a difference in the typical case where the result is used as a primitive value.
|
||||
|
||||
- System.MarshalByRefObject is translated to java.lang.Object.
|
||||
- `System.MarshalByRefObject` is translated to `java.lang.Object`.
|
||||
|
||||
- Attribute [MethodImplOptions.Synchronized] is not supported on constructors.
|
||||
- Attribute `[MethodImplOptions.Synchronized]` is not supported on constructors.
|
||||
|
||||
- Module-level and assembly-level constructors/initializers are not supported.
|
||||
|
||||
- AbandonedMutexException is not supported. Any mutex objects still held at time of thread death will never be released.
|
||||
- `AbandonedMutexException` is not supported. Any mutex objects still held at time of thread death will never be released.
|
||||
|
||||
- The GetHashCode implementions attempt to match those in the .NET Framework, which are not necessarily the same as the implementations in .NET Core.
|
||||
- The `GetHashCode` implementions attempt to match those in the .NET Framework, which are not necessarily the same as the implementations in .NET Core.
|
||||
|
||||
- StringBuilder does not support a maximum capacity.
|
||||
- `StringBuilder` does not support a maximum capacity.
|
||||
|
||||
- Standard numeric format strings are supported, but a custom format, or a non-null IFormatProvider parameter in ToString functions will throw an exception.
|
||||
- Standard numeric format strings are supported, but a custom format, or an `IFormatProvider` which also implements `NumberFormatInfo` will cause `ToString` functions to throw an exception.
|
||||
|
||||
- Non-ordinal, culture-dependant string comparisons and casing are not 100% same, because of differences between Windows NLS and the java.text package.
|
||||
- Non-ordinal, culture-dependant string comparisons and casing are not 100% same, because of differences between Windows NLS and the `java.text` package.
|
||||
|
||||
- String is not castable to IConvertible or to the non-generic IComparable interface.
|
||||
- `String` is not castable to `IConvertible` or to the non-generic `IComparable` interface.
|
||||
|
Loading…
x
Reference in New Issue
Block a user