mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-04-29 06:48:41 +00:00
Tests
This commit is contained in:
+230
-227
@@ -267,263 +267,266 @@ namespace Esiur.Data
|
||||
// case TRUIdentifier. }
|
||||
//}
|
||||
|
||||
private static Dictionary<Type, Tru> _cache = new Dictionary<Type, Tru>();
|
||||
private static Dictionary<Type, Tru> cache = new Dictionary<Type, Tru>();
|
||||
private static object cacheLook = new object();
|
||||
|
||||
public static Tru? FromType(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
return new Tru(TruIdentifier.Void, true);
|
||||
|
||||
if (_cache.ContainsKey(type))
|
||||
return _cache[type];
|
||||
|
||||
var nullable = false;
|
||||
|
||||
var nullType = System.Nullable.GetUnderlyingType(type);
|
||||
|
||||
if (nullType != null)
|
||||
lock (cacheLook)
|
||||
{
|
||||
type = nullType;
|
||||
nullable = true;
|
||||
}
|
||||
if (cache.ContainsKey(type))
|
||||
return cache[type];
|
||||
|
||||
Tru? tru = null;
|
||||
var nullable = false;
|
||||
|
||||
if (type == typeof(IResource))
|
||||
{
|
||||
return new Tru(TruIdentifier.Resource, nullable);
|
||||
}
|
||||
else if (type == typeof(IRecord) || type == typeof(Record))
|
||||
{
|
||||
return new Tru(TruIdentifier.Record, nullable);
|
||||
}
|
||||
else if (type == typeof(Map<object, object>)
|
||||
|| type == typeof(Dictionary<object, object>))
|
||||
{
|
||||
return new Tru(TruIdentifier.Map, nullable);
|
||||
}
|
||||
else if (Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
{
|
||||
tru = new Tru(
|
||||
TruIdentifier.TypedResource,
|
||||
nullable,
|
||||
TypeDef.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
|
||||
{
|
||||
tru = new Tru(
|
||||
TruIdentifier.TypedRecord,
|
||||
nullable,
|
||||
TypeDef.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (type.IsGenericType)
|
||||
{
|
||||
var genericType = type.GetGenericTypeDefinition();
|
||||
var nullType = System.Nullable.GetUnderlyingType(type);
|
||||
|
||||
if (genericType == typeof(List<>)
|
||||
|| genericType == typeof(VarList<>)
|
||||
|| genericType == typeof(IList<>))
|
||||
if (nullType != null)
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object))
|
||||
type = nullType;
|
||||
nullable = true;
|
||||
}
|
||||
|
||||
Tru? tru = null;
|
||||
|
||||
if (type == typeof(IResource))
|
||||
{
|
||||
return new Tru(TruIdentifier.Resource, nullable);
|
||||
}
|
||||
else if (type == typeof(IRecord) || type == typeof(Record))
|
||||
{
|
||||
return new Tru(TruIdentifier.Record, nullable);
|
||||
}
|
||||
else if (type == typeof(Map<object, object>)
|
||||
|| type == typeof(Dictionary<object, object>))
|
||||
{
|
||||
return new Tru(TruIdentifier.Map, nullable);
|
||||
}
|
||||
else if (Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
{
|
||||
tru = new Tru(
|
||||
TruIdentifier.TypedResource,
|
||||
nullable,
|
||||
TypeDef.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
|
||||
{
|
||||
tru = new Tru(
|
||||
TruIdentifier.TypedRecord,
|
||||
nullable,
|
||||
TypeDef.GetTypeUUID(type)
|
||||
);
|
||||
}
|
||||
else if (type.IsGenericType)
|
||||
{
|
||||
var genericType = type.GetGenericTypeDefinition();
|
||||
|
||||
if (genericType == typeof(List<>)
|
||||
|| genericType == typeof(VarList<>)
|
||||
|| genericType == typeof(IList<>))
|
||||
{
|
||||
tru = new Tru(TruIdentifier.List, nullable);
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object))
|
||||
{
|
||||
tru = new Tru(TruIdentifier.List, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType = FromType(args[0]);
|
||||
if (subType == null) // unrecongnized type
|
||||
return null;
|
||||
|
||||
|
||||
tru = new Tru(TruIdentifier.TypedList, nullable, null,
|
||||
new Tru[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (genericType == typeof(Map<,>)
|
||||
|| genericType == typeof(Dictionary<,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object) && args[1] == typeof(object))
|
||||
{
|
||||
tru = new Tru(TruIdentifier.Map, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType1 = FromType(args[0]);
|
||||
if (subType1 == null)
|
||||
return null;
|
||||
|
||||
var subType2 = FromType(args[1]);
|
||||
if (subType2 == null)
|
||||
return null;
|
||||
|
||||
tru = new Tru(TruIdentifier.TypedMap, nullable, null,
|
||||
new Tru[] { subType1, subType2 });
|
||||
|
||||
}
|
||||
}
|
||||
else if (genericType == typeof(ResourceLink<>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
|
||||
return FromType(args[0]);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple2, nullable, null, subTypes);
|
||||
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple3, nullable, null, subTypes);
|
||||
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,>))
|
||||
{
|
||||
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple4, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple5, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple6, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple7, nullable, null, subTypes);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
var elementType = type.GetElementType();
|
||||
if (elementType == typeof(object))
|
||||
tru = new Tru(TruIdentifier.List, nullable);
|
||||
else
|
||||
{
|
||||
var subType = FromType(args[0]);
|
||||
if (subType == null) // unrecongnized type
|
||||
return null;
|
||||
var subType = FromType(elementType);
|
||||
|
||||
if (subType == null)
|
||||
return null;
|
||||
|
||||
tru = new Tru(TruIdentifier.TypedList, nullable, null,
|
||||
new Tru[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (genericType == typeof(Map<,>)
|
||||
|| genericType == typeof(Dictionary<,>))
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
if (args[0] == typeof(object) && args[1] == typeof(object))
|
||||
{
|
||||
tru = new Tru(TruIdentifier.Map, nullable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subType1 = FromType(args[0]);
|
||||
if (subType1 == null)
|
||||
return null;
|
||||
|
||||
var subType2 = FromType(args[1]);
|
||||
if (subType2 == null)
|
||||
return null;
|
||||
|
||||
tru = new Tru(TruIdentifier.TypedMap, nullable, null,
|
||||
new Tru[] { subType1, subType2 });
|
||||
|
||||
}
|
||||
tru = new Tru(TruIdentifier.Enum, nullable, TypeDef.GetTypeUUID(type));
|
||||
}
|
||||
else if (genericType == typeof(ResourceLink<>))
|
||||
else if (type.IsInterface)
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
|
||||
return FromType(args[0]);
|
||||
return null; // other interfaces are not supported
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,>))
|
||||
|
||||
//else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => TRUIdentifier.Structure)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
if (tru != null)
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple2, nullable, null, subTypes);
|
||||
|
||||
cache.Add(type, tru);
|
||||
return tru;
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,>))
|
||||
|
||||
// last check
|
||||
return type switch
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple3, nullable, null, subTypes);
|
||||
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,>))
|
||||
{
|
||||
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple4, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple5, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple6, nullable, null, subTypes);
|
||||
}
|
||||
else if (genericType == typeof(ValueTuple<,,,,,,>))
|
||||
{
|
||||
var args = type.GetGenericArguments();
|
||||
var subTypes = new Tru[args.Length];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var t = FromType(args[i]);
|
||||
if (t == null)
|
||||
return null;
|
||||
subTypes[i] = t;
|
||||
}
|
||||
|
||||
tru = new Tru(TruIdentifier.Tuple7, nullable, null, subTypes);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
_ when type == typeof(void) => new Tru(TruIdentifier.Void, nullable),
|
||||
_ when type == typeof(object) => new Tru(TruIdentifier.Dynamic, nullable),
|
||||
_ when type == typeof(bool) => new Tru(TruIdentifier.Bool, nullable),
|
||||
_ when type == typeof(char) => new Tru(TruIdentifier.Char, nullable),
|
||||
_ when type == typeof(byte) => new Tru(TruIdentifier.UInt8, nullable),
|
||||
_ when type == typeof(sbyte) => new Tru(TruIdentifier.Int8, nullable),
|
||||
_ when type == typeof(short) => new Tru(TruIdentifier.Int16, nullable),
|
||||
_ when type == typeof(ushort) => new Tru(TruIdentifier.UInt16, nullable),
|
||||
_ when type == typeof(int) => new Tru(TruIdentifier.Int32, nullable),
|
||||
_ when type == typeof(uint) => new Tru(TruIdentifier.UInt32, nullable),
|
||||
_ when type == typeof(long) => new Tru(TruIdentifier.Int64, nullable),
|
||||
_ when type == typeof(ulong) => new Tru(TruIdentifier.UInt64, nullable),
|
||||
_ when type == typeof(float) => new Tru(TruIdentifier.Float32, nullable),
|
||||
_ when type == typeof(double) => new Tru(TruIdentifier.Float64, nullable),
|
||||
_ when type == typeof(decimal) => new Tru(TruIdentifier.Decimal, nullable),
|
||||
_ when type == typeof(string) => new Tru(TruIdentifier.String, nullable),
|
||||
_ when type == typeof(DateTime) => new Tru(TruIdentifier.DateTime, nullable),
|
||||
_ when type == typeof(ResourceLink) => new Tru(TruIdentifier.Resource, nullable),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
var elementType = type.GetElementType();
|
||||
if (elementType == typeof(object))
|
||||
tru = new Tru(TruIdentifier.List, nullable);
|
||||
else
|
||||
{
|
||||
var subType = FromType(elementType);
|
||||
|
||||
if (subType == null)
|
||||
return null;
|
||||
|
||||
tru = new Tru(TruIdentifier.TypedList, nullable, null,
|
||||
new Tru[] { subType });
|
||||
|
||||
}
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
tru = new Tru(TruIdentifier.Enum, nullable, TypeDef.GetTypeUUID(type));
|
||||
}
|
||||
else if (type.IsInterface)
|
||||
{
|
||||
return null; // other interfaces are not supported
|
||||
}
|
||||
|
||||
//else if (typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => TRUIdentifier.Structure)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
if (tru != null)
|
||||
{
|
||||
_cache.Add(type, tru);
|
||||
return tru;
|
||||
}
|
||||
|
||||
// last check
|
||||
return type switch
|
||||
{
|
||||
_ when type == typeof(void) => new Tru(TruIdentifier.Void, nullable),
|
||||
_ when type == typeof(object) => new Tru(TruIdentifier.Dynamic, nullable),
|
||||
_ when type == typeof(bool) => new Tru(TruIdentifier.Bool, nullable),
|
||||
_ when type == typeof(char) => new Tru(TruIdentifier.Char, nullable),
|
||||
_ when type == typeof(byte) => new Tru(TruIdentifier.UInt8, nullable),
|
||||
_ when type == typeof(sbyte) => new Tru(TruIdentifier.Int8, nullable),
|
||||
_ when type == typeof(short) => new Tru(TruIdentifier.Int16, nullable),
|
||||
_ when type == typeof(ushort) => new Tru(TruIdentifier.UInt16, nullable),
|
||||
_ when type == typeof(int) => new Tru(TruIdentifier.Int32, nullable),
|
||||
_ when type == typeof(uint) => new Tru(TruIdentifier.UInt32, nullable),
|
||||
_ when type == typeof(long) => new Tru(TruIdentifier.Int64, nullable),
|
||||
_ when type == typeof(ulong) => new Tru(TruIdentifier.UInt64, nullable),
|
||||
_ when type == typeof(float) => new Tru(TruIdentifier.Float32, nullable),
|
||||
_ when type == typeof(double) => new Tru(TruIdentifier.Float64, nullable),
|
||||
_ when type == typeof(decimal) => new Tru(TruIdentifier.Decimal, nullable),
|
||||
_ when type == typeof(string) => new Tru(TruIdentifier.String, nullable),
|
||||
_ when type == typeof(DateTime) => new Tru(TruIdentifier.DateTime, nullable),
|
||||
_ when type == typeof(ResourceLink) => new Tru(TruIdentifier.Resource, nullable),
|
||||
_ => null
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public Tru(TruIdentifier identifier, bool nullable, Uuid? uuid = null, Tru[]? subTypes = null)
|
||||
|
||||
@@ -12,12 +12,12 @@ namespace Esiur.Net.Packets
|
||||
Stream = 0x2,
|
||||
|
||||
// Error
|
||||
PermissionError = 0x81,
|
||||
ExecutionError = 0x82,
|
||||
PermissionError = 0x4,
|
||||
ExecutionError = 0x5,
|
||||
|
||||
// Partial
|
||||
Progress = 0x10,
|
||||
Chunk = 0x11,
|
||||
Warning = 0x12
|
||||
Progress = 0x8,
|
||||
Chunk = 0x9,
|
||||
Warning = 0xA
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,11 @@ partial class EpConnection
|
||||
|
||||
Dictionary<Uuid, TypeDef> typeDefs = new Dictionary<Uuid, TypeDef>();
|
||||
|
||||
object typeDefsLock = new object();
|
||||
|
||||
KeyList<uint, AsyncReply> requests = new KeyList<uint, AsyncReply>();
|
||||
|
||||
volatile uint callbackCounter = 0;
|
||||
volatile int callbackCounter = 0;
|
||||
|
||||
Dictionary<IResource, List<byte>> subscriptions = new Dictionary<IResource, List<byte>>();
|
||||
|
||||
@@ -73,15 +75,18 @@ partial class EpConnection
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Send IIP request.
|
||||
/// Send EP request.
|
||||
/// </summary>
|
||||
/// <param name="action">Packet action.</param>
|
||||
/// <param name="args">Arguments to send.</param>
|
||||
/// <returns></returns>
|
||||
///
|
||||
|
||||
AsyncReply SendRequest(EpPacketRequest action, params object[] args)
|
||||
{
|
||||
var reply = new AsyncReply();
|
||||
var c = callbackCounter++; // avoid thread racing
|
||||
var c = (uint)Interlocked.Increment(ref callbackCounter);
|
||||
//callbackCounter++; // avoid thread racing
|
||||
requests.Add(c, reply);
|
||||
|
||||
if (args.Length == 0)
|
||||
@@ -112,7 +117,7 @@ partial class EpConnection
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send IIP notification.
|
||||
/// Send EP notification.
|
||||
/// </summary>
|
||||
/// <param name="action">Packet action.</param>
|
||||
/// <param name="args">Arguments to send.</param>
|
||||
@@ -343,7 +348,7 @@ partial class EpConnection
|
||||
var args = DataDeserializer.ListParser(dataType, Instance.Warehouse)
|
||||
as object[];
|
||||
|
||||
var errorCode = (ushort)args[0];
|
||||
var errorCode =Convert.ToUInt16( args[0]);
|
||||
var errorMsg = (string)args[1];
|
||||
|
||||
req.TriggerError(new AsyncException(type, errorCode, errorMsg));
|
||||
@@ -1721,60 +1726,66 @@ partial class EpConnection
|
||||
/// <returns>TypeSchema.</returns>
|
||||
public AsyncReply<TypeDef> GetTypeDefById(Uuid typeId)
|
||||
{
|
||||
if (typeDefs.ContainsKey(typeId))
|
||||
return new AsyncReply<TypeDef>(typeDefs[typeId]);
|
||||
else if (typeDefsByIdRequests.ContainsKey(typeId))
|
||||
return typeDefsByIdRequests[typeId];
|
||||
lock (typeDefsLock)
|
||||
{
|
||||
if (typeDefs.ContainsKey(typeId))
|
||||
return new AsyncReply<TypeDef>(typeDefs[typeId]);
|
||||
else if (typeDefsByIdRequests.ContainsKey(typeId))
|
||||
return typeDefsByIdRequests[typeId];
|
||||
|
||||
var reply = new AsyncReply<TypeDef>();
|
||||
typeDefsByIdRequests.Add(typeId, reply);
|
||||
var reply = new AsyncReply<TypeDef>();
|
||||
typeDefsByIdRequests.Add(typeId, reply);
|
||||
|
||||
SendRequest(EpPacketRequest.TypeDefById, typeId)
|
||||
.Then((result) =>
|
||||
{
|
||||
var tt = TypeDef.Parse((byte[])result);
|
||||
typeDefsByIdRequests.Remove(typeId);
|
||||
typeDefs.Add(tt.Id, tt);
|
||||
Instance.Warehouse.RegisterTypeDef(tt);
|
||||
reply.Trigger(tt);
|
||||
SendRequest(EpPacketRequest.TypeDefById, typeId)
|
||||
.Then((result) =>
|
||||
{
|
||||
var tt = TypeDef.Parse((byte[])result);
|
||||
typeDefsByIdRequests.Remove(typeId);
|
||||
typeDefs.Add(tt.Id, tt);
|
||||
Instance.Warehouse.RegisterTypeDef(tt);
|
||||
reply.Trigger(tt);
|
||||
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
|
||||
return reply;
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AsyncReply<TypeDef> GetTypeDefByName(string typeName)
|
||||
{
|
||||
var typeDef = typeDefs.Values.FirstOrDefault(x => x.Name == typeName);
|
||||
if (typeDef != null)
|
||||
return new AsyncReply<TypeDef>(typeDef);
|
||||
lock (typeDefsLock)
|
||||
{
|
||||
var typeDef = typeDefs.Values.FirstOrDefault(x => x.Name == typeName);
|
||||
if (typeDef != null)
|
||||
return new AsyncReply<TypeDef>(typeDef);
|
||||
|
||||
if (typeDefsByNameRequests.ContainsKey(typeName))
|
||||
return typeDefsByNameRequests[typeName];
|
||||
if (typeDefsByNameRequests.ContainsKey(typeName))
|
||||
return typeDefsByNameRequests[typeName];
|
||||
|
||||
var reply = new AsyncReply<TypeDef>();
|
||||
typeDefsByNameRequests.Add(typeName, reply);
|
||||
var reply = new AsyncReply<TypeDef>();
|
||||
typeDefsByNameRequests.Add(typeName, reply);
|
||||
|
||||
|
||||
SendRequest(EpPacketRequest.TypeDefByName, typeName)
|
||||
.Then((result) =>
|
||||
{
|
||||
var tt = TypeDef.Parse((byte[])result);
|
||||
SendRequest(EpPacketRequest.TypeDefByName, typeName)
|
||||
.Then((result) =>
|
||||
{
|
||||
var tt = TypeDef.Parse((byte[])result);
|
||||
|
||||
typeDefsByNameRequests.Remove(typeName);
|
||||
typeDefs.Add(tt.Id, tt);
|
||||
Instance.Warehouse.RegisterTypeDef(tt);
|
||||
reply.Trigger(tt);
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
typeDefsByNameRequests.Remove(typeName);
|
||||
typeDefs.Add(tt.Id, tt);
|
||||
Instance.Warehouse.RegisterTypeDef(tt);
|
||||
reply.Trigger(tt);
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
|
||||
return reply;
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
// IStore interface
|
||||
@@ -1846,156 +1857,162 @@ partial class EpConnection
|
||||
/// </summary>
|
||||
/// <param name="id">Resource Id</param>
|
||||
/// <returns>DistributedResource</returns>
|
||||
///
|
||||
object fetchLock = new object();
|
||||
public AsyncReply<EpResource> Fetch(uint id, uint[] requestSequence)
|
||||
{
|
||||
//lock (fetchLock)
|
||||
//{
|
||||
EpResource resource = null;
|
||||
|
||||
EpResource resource = null;
|
||||
attachedResources[id]?.TryGetTarget(out resource);
|
||||
|
||||
attachedResources[id]?.TryGetTarget(out resource);
|
||||
|
||||
if (resource != null)
|
||||
return new AsyncReply<EpResource>(resource);
|
||||
|
||||
resource = neededResources[id];
|
||||
|
||||
var requestInfo = resourceRequests[id];
|
||||
|
||||
if (requestInfo != null)
|
||||
{
|
||||
if (resource != null && (requestSequence?.Contains(id) ?? false))
|
||||
{
|
||||
// dead lock avoidance for loop reference.
|
||||
if (resource != null)
|
||||
return new AsyncReply<EpResource>(resource);
|
||||
}
|
||||
else if (resource != null && requestInfo.RequestSequence.Contains(id))
|
||||
|
||||
resource = neededResources[id];
|
||||
|
||||
var requestInfo = resourceRequests[id];
|
||||
|
||||
if (requestInfo != null)
|
||||
{
|
||||
// dead lock avoidance for dependent reference.
|
||||
if (resource != null && (requestSequence?.Contains(id) ?? false))
|
||||
{
|
||||
// dead lock avoidance for loop reference.
|
||||
return new AsyncReply<EpResource>(resource);
|
||||
}
|
||||
else if (resource != null && requestInfo.RequestSequence.Contains(id))
|
||||
{
|
||||
// dead lock avoidance for dependent reference.
|
||||
return new AsyncReply<EpResource>(resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
return requestInfo.Reply;
|
||||
}
|
||||
}
|
||||
else if (resource != null && !resource.DistributedResourceSuspended)
|
||||
{
|
||||
// @REVIEW: this should never happen
|
||||
Global.Log("DCON", LogType.Error, "Resource not moved to attached.");
|
||||
return new AsyncReply<EpResource>(resource);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return requestInfo.Reply;
|
||||
}
|
||||
}
|
||||
else if (resource != null && !resource.DistributedResourceSuspended)
|
||||
{
|
||||
// @REVIEW: this should never happen
|
||||
Global.Log("DCON", LogType.Error, "Resource not moved to attached.");
|
||||
return new AsyncReply<EpResource>(resource);
|
||||
|
||||
}
|
||||
var newSequence = requestSequence != null ? requestSequence.Concat(new uint[] { id }).ToArray() : new uint[] { id };
|
||||
|
||||
var newSequence = requestSequence != null ? requestSequence.Concat(new uint[] { id }).ToArray() : new uint[] { id };
|
||||
var reply = new AsyncReply<EpResource>();
|
||||
resourceRequests.Add(id, new EpResourceAttachRequestInfo(reply, newSequence));
|
||||
|
||||
var reply = new AsyncReply<EpResource>();
|
||||
resourceRequests.Add(id, new EpResourceAttachRequestInfo(reply, newSequence));
|
||||
|
||||
SendRequest(EpPacketRequest.AttachResource, id)
|
||||
.Then((result) =>
|
||||
{
|
||||
if (result == null)
|
||||
SendRequest(EpPacketRequest.AttachResource, id)
|
||||
.Then((result) =>
|
||||
{
|
||||
reply.TriggerError(new AsyncException(ErrorType.Management,
|
||||
(ushort)ExceptionCode.ResourceNotFound, "Null response"));
|
||||
return;
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
reply.TriggerError(new AsyncException(ErrorType.Management,
|
||||
(ushort)ExceptionCode.ResourceNotFound, "Null response"));
|
||||
return;
|
||||
}
|
||||
|
||||
// TypeId, Age, Link, Hops, PropertyValue[]
|
||||
var args = (object[])result;
|
||||
var typeId = (Uuid)args[0];
|
||||
var age = Convert.ToUInt64(args[1]);
|
||||
var link = (string)args[2];
|
||||
var hops = (byte)args[3];
|
||||
var pvData = (byte[])args[4];
|
||||
// TypeId, Age, Link, Hops, PropertyValue[]
|
||||
var args = (object[])result;
|
||||
var typeId = (Uuid)args[0];
|
||||
var age = Convert.ToUInt64(args[1]);
|
||||
var link = (string)args[2];
|
||||
var hops = (byte)args[3];
|
||||
var pvData = (byte[])args[4];
|
||||
|
||||
|
||||
EpResource dr;
|
||||
TypeDef typeDef = null;
|
||||
EpResource dr;
|
||||
TypeDef typeDef = null;
|
||||
|
||||
if (resource == null)
|
||||
{
|
||||
typeDef = Instance.Warehouse.GetTypeDefById(typeId, TypeDefKind.Resource);
|
||||
if (typeDef?.DefinedType != null && typeDef.IsWrapper)
|
||||
dr = Activator.CreateInstance(typeDef.DefinedType, this, id, Convert.ToUInt64(args[1]), (string)args[2]) as EpResource;
|
||||
if (resource == null)
|
||||
{
|
||||
typeDef = Instance.Warehouse.GetTypeDefById(typeId, TypeDefKind.Resource);
|
||||
if (typeDef?.DefinedType != null && typeDef.IsWrapper)
|
||||
dr = Activator.CreateInstance(typeDef.DefinedType, this, id, Convert.ToUInt64(args[1]), (string)args[2]) as EpResource;
|
||||
else
|
||||
dr = new EpResource(this, id, Convert.ToUInt64(args[1]), (string)args[2]);
|
||||
}
|
||||
else
|
||||
dr = new EpResource(this, id, Convert.ToUInt64(args[1]), (string)args[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
dr = resource;
|
||||
typeDef = resource.Instance.Definition;
|
||||
}
|
||||
|
||||
|
||||
var initResource = (EpResource ok) =>
|
||||
{
|
||||
var parsedReply = DataDeserializer.PropertyValueArrayParserAsync(pvData, 0, (uint)pvData.Length, this, newSequence);// Codec.proper (content, 0, this, newSequence, transmissionType);
|
||||
|
||||
|
||||
parsedReply.Then(results =>
|
||||
{
|
||||
var pvs = results as PropertyValue[];
|
||||
|
||||
//var pvs = new List<PropertyValue>();
|
||||
|
||||
//for (var i = 0; i < ar.Length; i += 3)
|
||||
// pvs.Add(new PropertyValue(ar[i + 2], Convert.ToUInt64(ar[i]), (DateTime)ar[i + 1]));
|
||||
|
||||
dr._Attach(pvs);
|
||||
resourceRequests.Remove(id);
|
||||
// move from needed to attached.
|
||||
neededResources.Remove(id);
|
||||
attachedResources[id] = new WeakReference<EpResource>(dr);
|
||||
reply.Trigger(dr);
|
||||
}).Error(ex => reply.TriggerError(ex));
|
||||
dr = resource;
|
||||
typeDef = resource.Instance.Definition;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
if (typeDef == null)
|
||||
{
|
||||
GetTypeDefById(typeId).Then((tmp) =>
|
||||
var initResource = (EpResource ok) =>
|
||||
{
|
||||
var parsedReply = DataDeserializer.PropertyValueArrayParserAsync(pvData, 0, (uint)pvData.Length, this, newSequence);// Codec.proper (content, 0, this, newSequence, transmissionType);
|
||||
|
||||
|
||||
parsedReply.Then(results =>
|
||||
{
|
||||
var pvs = results as PropertyValue[];
|
||||
|
||||
//var pvs = new List<PropertyValue>();
|
||||
|
||||
//for (var i = 0; i < ar.Length; i += 3)
|
||||
// pvs.Add(new PropertyValue(ar[i + 2], Convert.ToUInt64(ar[i]), (DateTime)ar[i + 1]));
|
||||
|
||||
dr._Attach(pvs);
|
||||
resourceRequests.Remove(id);
|
||||
// move from needed to attached.
|
||||
neededResources.Remove(id);
|
||||
attachedResources[id] = new WeakReference<EpResource>(dr);
|
||||
reply.Trigger(dr);
|
||||
}).Error(ex => reply.TriggerError(ex));
|
||||
|
||||
|
||||
};
|
||||
|
||||
if (typeDef == null)
|
||||
{
|
||||
GetTypeDefById(typeId).Then((tmp) =>
|
||||
{
|
||||
// typeId, ResourceAge, ResourceLink, Content
|
||||
if (resource == null)
|
||||
{
|
||||
dr.ResourceDefinition = tmp;
|
||||
|
||||
Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr)
|
||||
.Then(initResource)
|
||||
.Error(ex => reply.TriggerError(ex));
|
||||
}
|
||||
else
|
||||
{
|
||||
initResource(resource);
|
||||
}
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// typeId, ResourceAge, ResourceLink, Content
|
||||
if (resource == null)
|
||||
{
|
||||
dr.ResourceDefinition = tmp;
|
||||
dr.ResourceDefinition = typeDef;
|
||||
|
||||
Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr)
|
||||
.Then(initResource)
|
||||
.Error(ex => reply.TriggerError(ex));
|
||||
.Then(initResource).Error((ex) => reply.TriggerError(ex));
|
||||
}
|
||||
else
|
||||
{
|
||||
initResource(resource);
|
||||
}
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
}).Error((ex) =>
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
Instance.Warehouse.Put(this.Instance.Link + "/" + id.ToString(), dr)
|
||||
.Then(initResource).Error((ex) => reply.TriggerError(ex));
|
||||
}
|
||||
else
|
||||
{
|
||||
initResource(resource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}).Error((ex) =>
|
||||
{
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
reply.TriggerError(ex);
|
||||
});
|
||||
|
||||
|
||||
return reply;
|
||||
return reply;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -117,30 +117,6 @@ namespace Esiur.Proxy
|
||||
}
|
||||
}
|
||||
|
||||
// var code = @$"using Esiur.Resource;
|
||||
//using Esiur.Core;
|
||||
|
||||
//#nullable enable
|
||||
|
||||
//namespace {ci.ClassSymbol.ContainingNamespace.ToDisplayString()} {{
|
||||
//";
|
||||
|
||||
// if (IsInterfaceImplemented(ci, classes))
|
||||
// code += $"public partial class {ci.Name} {{\r\n";
|
||||
// else
|
||||
// {
|
||||
// code +=
|
||||
//$@" public partial class {ci.Name} : IResource {{
|
||||
// public virtual Instance? Instance {{ get; set; }}
|
||||
// public virtual event DestroyedEvent? OnDestroy;
|
||||
|
||||
// public virtual void Destroy() {{ OnDestroy?.Invoke(this); }}
|
||||
//";
|
||||
|
||||
// if (!ci.HasTrigger)
|
||||
// code += "\tpublic virtual AsyncReply<bool> Trigger(ResourceTrigger trigger) => new AsyncReply<bool>(true);\r\n\r\n";
|
||||
// }
|
||||
|
||||
foreach (var f in ci.Fields)
|
||||
{
|
||||
var givenName = f.GetAttributes().FirstOrDefault(x => x.AttributeClass?.Name == "ExportAttribute")?.ConstructorArguments.FirstOrDefault().Value as string;
|
||||
@@ -156,12 +132,17 @@ namespace Esiur.Proxy
|
||||
|
||||
if (f.Type.Name.StartsWith("ResourceEventHandler") || f.Type.Name.StartsWith("CustomResourceEventHandler"))
|
||||
{
|
||||
code.AppendLine($"public event {f.Type} {pn};");
|
||||
code.AppendLine($"\tpublic event {f.Type} {pn};");
|
||||
}
|
||||
else
|
||||
{
|
||||
code.AppendLine($"\t{attrs}\r\n\t public {f.Type} {pn} {{ \r\n\t\t get => {fn}; \r\n\t\t set {{ \r\n\t\t this.{fn} = value; \r\n\t\t Instance?.Modified(); \r\n\t\t}}\r\n\t}}\r\n");
|
||||
|
||||
code.AppendLine($"\tpublic {f.Type} {pn} {{");
|
||||
code.AppendLine($"\t\t get => {fn};");
|
||||
code.AppendLine($"\t\t set {{");
|
||||
code.AppendLine($"\t\t this.{fn} = value;");
|
||||
code.AppendLine($"\t\t Instance?.Modified();");
|
||||
code.AppendLine($"\t\t}}");
|
||||
code.AppendLine($"\t}}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Esiur.Proxy;
|
||||
public static class ResourceProxy
|
||||
{
|
||||
static Dictionary<Type, Type> cache = new Dictionary<Type, Type>();
|
||||
static object cacheLock = new object();
|
||||
|
||||
#if NETSTANDARD
|
||||
static MethodInfo modifyMethod = typeof(Instance).GetTypeInfo().GetMethod("Modified");
|
||||
@@ -48,33 +49,34 @@ public static class ResourceProxy
|
||||
|
||||
public static Type GetProxy(Type type)
|
||||
{
|
||||
|
||||
if (cache.ContainsKey(type))
|
||||
return cache[type];
|
||||
|
||||
// check if the type was made with code generation
|
||||
if (type.GetCustomAttribute<ResourceAttribute>(false) != null)
|
||||
lock (cacheLock)
|
||||
{
|
||||
cache.Add(type, type);
|
||||
return type;
|
||||
}
|
||||
if (cache.ContainsKey(type))
|
||||
return cache[type];
|
||||
|
||||
if (!Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
{
|
||||
cache.Add(type, type);
|
||||
return type;
|
||||
}
|
||||
// check if the type was made with code generation
|
||||
if (type.GetCustomAttribute<ResourceAttribute>(false) != null)
|
||||
{
|
||||
cache.Add(type, type);
|
||||
return type;
|
||||
}
|
||||
|
||||
if (!Codec.ImplementsInterface(type, typeof(IResource)))
|
||||
{
|
||||
cache.Add(type, type);
|
||||
return type;
|
||||
}
|
||||
|
||||
#if NETSTANDARD
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
|
||||
if (typeInfo.IsSealed || typeInfo.IsAbstract)
|
||||
throw new Exception("Sealed/Abastract classes can't be proxied.");
|
||||
if (typeInfo.IsSealed || typeInfo.IsAbstract)
|
||||
throw new Exception("Sealed/Abastract classes can't be proxied.");
|
||||
|
||||
var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal &&
|
||||
p.GetCustomAttribute<ExportAttribute>(false) != null
|
||||
select p;
|
||||
var props = from p in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
where p.CanWrite && p.SetMethod.IsVirtual && !p.SetMethod.IsFinal &&
|
||||
p.GetCustomAttribute<ExportAttribute>(false) != null
|
||||
select p;
|
||||
|
||||
#else
|
||||
if (type.IsSealed)
|
||||
@@ -86,33 +88,34 @@ public static class ResourceProxy
|
||||
select p;
|
||||
|
||||
#endif
|
||||
var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace);
|
||||
assemblyName.Version = type.Assembly.GetName().Version;
|
||||
assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo;
|
||||
//assemblyName.SetPublicKeyToken(null);
|
||||
var assemblyName = new AssemblyName("Esiur.Proxy.T." + type.Assembly.GetName().Name);// type.Namespace);
|
||||
assemblyName.Version = type.Assembly.GetName().Version;
|
||||
assemblyName.CultureInfo = type.Assembly.GetName().CultureInfo;
|
||||
//assemblyName.SetPublicKeyToken(null);
|
||||
|
||||
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||||
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
|
||||
var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName);
|
||||
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||||
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
|
||||
var typeName = "Esiur.Proxy.T." + type.FullName;// Assembly.CreateQualifiedName(assemblyName.FullName, "Esiur.Proxy.T." + type.FullName);
|
||||
|
||||
var typeBuilder = moduleBuilder.DefineType(typeName,
|
||||
TypeAttributes.Public | TypeAttributes.Class, type);
|
||||
var typeBuilder = moduleBuilder.DefineType(typeName,
|
||||
TypeAttributes.Public | TypeAttributes.Class, type);
|
||||
|
||||
foreach (PropertyInfo propertyInfo in props)
|
||||
CreateProperty(propertyInfo, typeBuilder, type);
|
||||
foreach (PropertyInfo propertyInfo in props)
|
||||
CreateProperty(propertyInfo, typeBuilder, type);
|
||||
|
||||
|
||||
|
||||
#if NETSTANDARD
|
||||
var t = typeBuilder.CreateTypeInfo().AsType();
|
||||
cache.Add(type, t);
|
||||
return t;
|
||||
var t = typeBuilder.CreateTypeInfo().AsType();
|
||||
cache.Add(type, t);
|
||||
return t;
|
||||
#else
|
||||
|
||||
var t = typeBuilder.CreateType();
|
||||
cache.Add(type, t);
|
||||
return t;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static Type GetProxy<T>()
|
||||
|
||||
@@ -753,7 +753,7 @@ public class Instance
|
||||
}
|
||||
else
|
||||
{
|
||||
this.definition = Warehouse.GetTypeDefByType(resource.GetType());
|
||||
this.definition = warehouse.GetTypeDefByType(resource.GetType());
|
||||
}
|
||||
|
||||
// set ages
|
||||
|
||||
@@ -67,6 +67,8 @@ public class Warehouse
|
||||
[TypeDefKind.Enum] = new KeyList<Uuid, TypeDef>(),
|
||||
};
|
||||
|
||||
object typeDefsLock = new object();
|
||||
|
||||
bool warehouseIsOpen = false;
|
||||
|
||||
public delegate void StoreEvent(IStore store);
|
||||
@@ -508,10 +510,13 @@ public class Warehouse
|
||||
/// <param name="typeDef">Resource type definition.</param>
|
||||
public void RegisterTypeDef(TypeDef typeDef)
|
||||
{
|
||||
if (typeDefs[typeDef.Kind].ContainsKey(typeDef.Id))
|
||||
throw new Exception($"TypeDef with same class Id already exists. {typeDefs[typeDef.Kind][typeDef.Id].Name} -> {typeDef.Name}");
|
||||
lock (typeDefsLock)
|
||||
{
|
||||
if (typeDefs[typeDef.Kind].ContainsKey(typeDef.Id))
|
||||
throw new Exception($"TypeDef with same class Id already exists. {typeDefs[typeDef.Kind][typeDef.Id].Name} -> {typeDef.Name}");
|
||||
|
||||
typeDefs[typeDef.Kind][typeDef.Id] = typeDef;
|
||||
typeDefs[typeDef.Kind][typeDef.Id] = typeDef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -522,9 +527,11 @@ public class Warehouse
|
||||
/// <returns>Resource TypeDef.</returns>
|
||||
public TypeDef GetTypeDefByType(Type type)
|
||||
{
|
||||
|
||||
if (!(type.IsClass || type.IsEnum))
|
||||
return null;
|
||||
|
||||
|
||||
var baseType = ResourceProxy.GetBaseType(type);
|
||||
|
||||
if (baseType == typeof(IResource)
|
||||
@@ -541,15 +548,17 @@ public class Warehouse
|
||||
else
|
||||
return null;
|
||||
|
||||
var typeDef = typeDefs[typeDefKind].Values.FirstOrDefault(x => x.DefinedType == baseType);
|
||||
if (typeDef != null)
|
||||
lock (typeDefsLock)
|
||||
{
|
||||
var typeDef = typeDefs[typeDefKind].Values.FirstOrDefault(x => x.DefinedType == baseType);
|
||||
if (typeDef != null)
|
||||
return typeDef;
|
||||
|
||||
// create new TypeDef for type
|
||||
typeDef = new TypeDef(baseType, this);
|
||||
TypeDef.GetDependencies(typeDef, this);
|
||||
return typeDef;
|
||||
|
||||
// create new TypeDef for type
|
||||
typeDef = new TypeDef(baseType, this);
|
||||
TypeDef.GetDependencies(typeDef, this);
|
||||
|
||||
return typeDef;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user