2
0
mirror of https://github.com/esiur/esiur-dotnet.git synced 2025-06-27 05:23:13 +00:00

Static Arrays

This commit is contained in:
2021-07-14 05:14:26 +03:00
parent d6b2a27221
commit 7940c152f0
24 changed files with 384 additions and 491 deletions

View File

@ -28,7 +28,7 @@ namespace Esiur.Resource
WeakReference<IResource> resource;
IStore store;
ResourceTemplate template;
TypeTemplate template;
AutoList<IPermissionsManager, Instance> managers;
@ -794,7 +794,7 @@ namespace Esiur.Resource
/// <summary>
/// Resource template describes the properties, functions and events of the resource.
/// </summary>
public ResourceTemplate Template
public TypeTemplate Template
{
get { return template; }
@ -853,7 +853,7 @@ namespace Esiur.Resource
/// <param name="name">Name of the instance.</param>
/// <param name="resource">Resource to manage.</param>
/// <param name="store">Store responsible for the resource.</param>
public Instance(uint id, string name, IResource resource, IStore store, ResourceTemplate customTemplate = null, ulong age = 0)
public Instance(uint id, string name, IResource resource, IStore store, TypeTemplate customTemplate = null, ulong age = 0)
{
this.store = store;
this.resource = new WeakReference<IResource>(resource);
@ -897,7 +897,7 @@ namespace Esiur.Resource
foreach (var evt in template.Events)
{
//if (evt.EventHandlerType != typeof(ResourceEventHanlder))
//if (evt.EventHandlerType != typeof(ResourceEventHandler))
// continue;
if (evt.EventInfo == null)
@ -905,24 +905,24 @@ namespace Esiur.Resource
var eventGenericType = evt.EventInfo.EventHandlerType.GetGenericTypeDefinition();
if (eventGenericType == typeof(ResourceEventHanlder<>))
if (eventGenericType == typeof(ResourceEventHandler<>))
{
// var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
// if (ca.Length == 0)
// continue;
ResourceEventHanlder<object> proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
ResourceEventHandler<object> proxyDelegate = (args) => EmitResourceEvent(evt.Name, args);
evt.EventInfo.AddEventHandler(resource, proxyDelegate);
}
else if (eventGenericType == typeof(CustomResourceEventHanlder<>))
else if (eventGenericType == typeof(CustomResourceEventHandler<>))
{
//var ca = (ResourceEvent[])evt.GetCustomAttributes(typeof(ResourceEvent), true);
//if (ca.Length == 0)
// continue;
CustomResourceEventHanlder<object> proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
CustomResourceEventHandler<object> proxyDelegate = (issuer, receivers, args) => EmitCustomResourceEvent(issuer, receivers, evt.Name, args);
evt.EventInfo.AddEventHandler(resource, proxyDelegate);
}

View File

@ -35,12 +35,12 @@ namespace Esiur.Resource
{
public delegate R DCovariant<out R>();
public delegate void ResourceEventHanlder<in T>(T argument);
public delegate void ResourceEventHandler<in T>(T argument);
// public delegate void CustomUsersEventHanlder(string[] usernames, params object[] args);
//public delegate void CustomReceiversEventHanlder(DistributedConnection[] connections, params object[] args);
//public delegate void CustomInquirerEventHanlder(object inquirer, params object[] args);
public delegate void CustomResourceEventHanlder<in T>(object issuer, Func<Session, bool> receivers, T argument);// object issuer, Session[] receivers, params object[] args);
public delegate void CustomResourceEventHandler<in T>(object issuer, Func<Session, bool> receivers, T argument);// object issuer, Session[] receivers, params object[] args);
// public delegate void CustomReceiversEventHanlder(string[] usernames, DistributedConnection[] connections, params object[] args);

View File

@ -17,7 +17,7 @@ namespace Esiur.Resource.Template
}
public AttributeTemplate(ResourceTemplate template, byte index, string name)
public AttributeTemplate(TypeTemplate template, byte index, string name)
: base(template, MemberType.Attribute, index, name)
{

View File

@ -48,7 +48,7 @@ namespace Esiur.Resource.Template
}
public EventTemplate(ResourceTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false)
public EventTemplate(TypeTemplate template, byte index, string name, TemplateDataType argumentType, string expansion = null, bool listenable=false)
:base(template, MemberType.Property, index, name)
{
this.Expansion = expansion;

View File

@ -64,7 +64,7 @@ namespace Esiur.Resource.Template
}
public FunctionTemplate(ResourceTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null)
public FunctionTemplate(TypeTemplate template, byte index, string name, ArgumentTemplate[] arguments, TemplateDataType returnType, string expansion = null)
: base(template, MemberType.Property, index, name)
{
//this.IsVoid = isVoid;

View File

@ -21,14 +21,14 @@ namespace Esiur.Resource.Template
public string Name => name;
public MemberType Type => type;
ResourceTemplate template;
TypeTemplate template;
string name;
MemberType type;
byte index;
public ResourceTemplate Template => template;
public TypeTemplate Template => template;
public MemberTemplate(ResourceTemplate template, MemberType type, byte index, string name)
public MemberTemplate(TypeTemplate template, MemberType type, byte index, string name)
{
this.template = template;
this.type = type;

View File

@ -130,7 +130,7 @@ namespace Esiur.Resource.Template
}
}
public PropertyTemplate(ResourceTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false)
public PropertyTemplate(TypeTemplate template, byte index, string name, TemplateDataType valueType, string read = null, string write = null, bool recordable = false)
: base(template, MemberType.Property, index, name)
{
this.Recordable = recordable;

View File

@ -1,277 +0,0 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Esiur.Resource.Template
{
public class RecordTemplate : ResourceTemplate
{
//Guid classId;
//public Guid ClassId => classId;
//string className;
//public string ClassName => className;
public RecordTemplate()
{
}
public new static RecordTemplate Parse(byte[] data, uint offset, uint contentLength)
{
uint ends = offset + contentLength;
uint oOffset = offset;
// start parsing...
var od = new RecordTemplate();
od.content = data.Clip(offset, contentLength);
od.classId = data.GetGuid(offset);
offset += 16;
od.className = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
od.version = data.GetInt32(offset);
offset += 4;
ushort methodsCount = data.GetUInt16(offset);
offset += 2;
for (int i = 0; i < methodsCount; i++)
{
var type = data[offset] >> 5;
if (type == 0) // function
{
string expansion = null;
var hasExpansion = ((data[offset++] & 0x10) == 0x10);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
// return type
var (rts, returnType) = TemplateDataType.Parse(data, offset);
offset += rts;
// arguments count
var argsCount = data[offset++];
List<ArgumentTemplate> arguments = new();
for (var a = 0; a < argsCount; a++)
{
var (cs, argType) = ArgumentTemplate.Parse(data, offset);
arguments.Add(argType);
offset += cs;
}
// arguments
if (hasExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
expansion = data.GetString(offset, cs);
offset += cs;
}
var ft = new FunctionTemplate(od, functionIndex++, name, arguments.ToArray(), returnType, expansion);
od.functions.Add(ft);
}
else if (type == 1) // property
{
string readExpansion = null, writeExpansion = null;
var hasReadExpansion = ((data[offset] & 0x8) == 0x8);
var hasWriteExpansion = ((data[offset] & 0x10) == 0x10);
var recordable = ((data[offset] & 1) == 1);
var permission = (PropertyTemplate.PropertyPermission)((data[offset++] >> 1) & 0x3);
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
var (dts, valueType) = TemplateDataType.Parse(data, offset);
offset += dts;
if (hasReadExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
readExpansion = data.GetString(offset, cs);
offset += cs;
}
if (hasWriteExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
writeExpansion = data.GetString(offset, cs);
offset += cs;
}
var pt = new PropertyTemplate(od, propertyIndex++, name, valueType, readExpansion, writeExpansion, recordable);
od.properties.Add(pt);
}
else if (type == 2) // Event
{
string expansion = null;
var hasExpansion = ((data[offset] & 0x10) == 0x10);
var listenable = ((data[offset++] & 0x8) == 0x8);
var name = data.GetString(offset + 1, data[offset]);// Encoding.ASCII.GetString(data, (int)offset + 1, (int)data[offset]);
offset += (uint)data[offset] + 1;
var (dts, argType) = TemplateDataType.Parse(data, offset);
offset += dts;
if (hasExpansion) // expansion ?
{
var cs = data.GetUInt32(offset);
offset += 4;
expansion = data.GetString(offset, cs);
offset += cs;
}
var et = new EventTemplate(od, eventIndex++, name, argType, expansion, listenable);
od.events.Add(et);
}
}
// append signals
for (int i = 0; i < od.events.Count; i++)
od.members.Add(od.events[i]);
// append slots
for (int i = 0; i < od.functions.Count; i++)
od.members.Add(od.functions[i]);
// append properties
for (int i = 0; i < od.properties.Count; i++)
od.members.Add(od.properties[i]);
//od.isReady = true;
/*
var oo = owner.Socket.Engine.GetObjectDescription(od.GUID);
if (oo != null)
{
Console.WriteLine("Already there ! description");
return oo;
}
else
{
owner.Socket.Engine.AddObjectDescription(od);
return od;
}
*/
return od;
}
public RecordTemplate(Type type)
{
if (!Codec.ImplementsInterface(type, typeof(IRecord)))
throw new Exception("Type is not a record.");
className = type.FullName;
classId = ResourceTemplate.GetTypeGuid(className);
#if NETSTANDARD
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);
#else
PropertyInfo[] propsInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
#endif
bool classIsPublic = type.GetCustomAttribute<PublicAttribute>() != null;
byte i = 0;
if (classIsPublic)
{
foreach (var pi in propsInfo)
{
var privateAttr = pi.GetCustomAttribute<PrivateAttribute>(true);
if (privateAttr == null)
continue;
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var pt = new PropertyTemplate(this, i++, pi.Name, TemplateDataType.FromType(pi.PropertyType));
if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
if (annotationAttr != null)
pt.ReadExpansion = annotationAttr.Annotation;
else
pt.ReadExpansion = pi.PropertyType.Name;
pt.PropertyInfo = pi;
//pt.Serilize = publicAttr.Serialize;
properties.Add(pt);
members.Add(pt);
}
}
else
{
foreach (var pi in propsInfo)
{
var publicAttr = pi.GetCustomAttribute<PublicAttribute>(true);
if (publicAttr == null)
continue;
var annotationAttr = pi.GetCustomAttribute<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var valueType = TemplateDataType.FromType(pi.PropertyType);
var pt = new PropertyTemplate(this, i++, pi.Name, valueType);//, rp.ReadExpansion, rp.WriteExpansion, rp.Storage);
if (storageAttr != null)
pt.Recordable = storageAttr.Mode == StorageMode.Recordable;
if (annotationAttr != null)
pt.ReadExpansion = annotationAttr.Annotation;
else
pt.ReadExpansion = pi.PropertyType.Name;
pt.PropertyInfo = pi;
//pt.Serilize = publicAttr.Serialize;
properties.Add(pt);
members.Add(pt);
}
}
// bake it binarily
var b = new BinaryList();
b.AddGuid(classId)
.AddUInt8((byte)className.Length)
.AddString(className)
.AddInt32(version)
.AddUInt16((ushort)members.Count);
foreach (var pt in properties)
b.AddUInt8Array(pt.Compose());
content = b.ToArray();
}
}
}

View File

@ -10,7 +10,7 @@ namespace Esiur.Resource.Template
{
public DataType Type { get; set; }
//public string TypeName { get; set; }
public ResourceTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid);
public TypeTemplate TypeTemplate => TypeGuid == null ? null : Warehouse.GetTemplateByClassId((Guid)TypeGuid);
public Guid? TypeGuid { get; set; }
//public TemplateDataType(DataType type, string typeName)
@ -49,6 +49,7 @@ namespace Esiur.Resource.Template
_ when t == typeof(string) => DataType.String,
_ when t == typeof(DateTime) => DataType.DateTime,
_ when t == typeof(IResource) => DataType.Void, // Dynamic resource (unspecified type)
_ when t == typeof(IRecord) => DataType.Void, // Dynamic record (unspecified type)
_ when typeof(Structure).IsAssignableFrom(t) || t == typeof(ExpandoObject) => DataType.Structure,
_ when Codec.ImplementsInterface(t, typeof(IResource)) => DataType.Resource,
_ when Codec.ImplementsInterface(t, typeof(IRecord)) => DataType.Record,
@ -59,7 +60,7 @@ namespace Esiur.Resource.Template
Guid? typeGuid = null;
if (dt == DataType.Resource || dt == DataType.Record)
typeGuid = ResourceTemplate.GetTypeGuid(t);
typeGuid = TypeTemplate.GetTypeGuid(t);
if (type.IsArray)
dt = (DataType)((byte)dt | 0x80);

View File

@ -6,7 +6,9 @@ namespace Esiur.Resource.Template
{
public enum TemplateType:byte
{
Unspecified,
Resource,
Record,
Wrapper,
}
}

View File

@ -18,7 +18,7 @@ namespace Esiur.Resource.Template
// Record
//}
public class ResourceTemplate
public class TypeTemplate
{
protected Guid classId;
@ -44,7 +44,7 @@ namespace Esiur.Resource.Template
public TemplateType Type => templateType;
public Type ResourceType { get; set; }
public Type DefinedType { get; set; }
@ -146,7 +146,7 @@ namespace Esiur.Resource.Template
public ResourceTemplate()
public TypeTemplate()
{
}
@ -171,18 +171,18 @@ namespace Esiur.Resource.Template
public static ResourceTemplate[] GetDependencies(ResourceTemplate template)
public static TypeTemplate[] GetDependencies(TypeTemplate template)
{
var list = new List<ResourceTemplate>();
var list = new List<TypeTemplate>();
list.Add(template);
Action<ResourceTemplate, List<ResourceTemplate>> getDependenciesFunc = null;
Action<TypeTemplate, List<TypeTemplate>> getDependenciesFunc = null;
getDependenciesFunc = (ResourceTemplate tmp, List<ResourceTemplate> bag) =>
getDependenciesFunc = (TypeTemplate tmp, List<TypeTemplate> bag) =>
{
if (template.ResourceType == null)
if (template.DefinedType == null)
return;
// functions
@ -267,14 +267,16 @@ namespace Esiur.Resource.Template
return list.ToArray();
}
public ResourceTemplate(Type type)
public TypeTemplate(Type type, bool addToWarehouse = false)
{
if (Codec.ImplementsInterface(type, typeof(IRecord)))
templateType = TemplateType.Record;
if (Codec.InheritsClass(type, typeof(DistributedResource)))
templateType = TemplateType.Wrapper;
else if (Codec.ImplementsInterface(type, typeof(IResource)))
templateType = TemplateType.Resource;
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
templateType = TemplateType.Record;
else
throw new Exception("Type is neither a resource nor a record.");
throw new Exception("Type must implement IResource, IRecord or inherit from DistributedResource.");
//if (isRecord && isResource)
// throw new Exception("Type can't have both IResource and IRecord interfaces");
@ -284,7 +286,7 @@ namespace Esiur.Resource.Template
type = ResourceProxy.GetBaseType(type);
ResourceType = type;
DefinedType = type;
className = type.FullName;
@ -292,7 +294,10 @@ namespace Esiur.Resource.Template
// set guid
classId = GetTypeGuid(className);
if (addToWarehouse)
Warehouse.PutTemplate(this);
#if NETSTANDARD
PropertyInfo[] propsInfo = type.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
EventInfo[] eventsInfo = type.GetTypeInfo().GetEvents(BindingFlags.Public | BindingFlags.Instance);// | BindingFlags.DeclaredOnly);
@ -395,8 +400,7 @@ namespace Esiur.Resource.Template
Name = x.Name,
Type = TemplateDataType.FromType(x.ParameterType),
ParameterInfo = x
})
.ToArray();
}).ToArray();
var ft = new FunctionTemplate(this, i++, mi.Name, arguments, returnType);// mi.ReturnType == typeof(void));
@ -546,13 +550,13 @@ namespace Esiur.Resource.Template
}
public static ResourceTemplate Parse(byte[] data)
public static TypeTemplate Parse(byte[] data)
{
return Parse(data, 0, (uint)data.Length);
}
public static ResourceTemplate Parse(byte[] data, uint offset, uint contentLength)
public static TypeTemplate Parse(byte[] data, uint offset, uint contentLength)
{
uint ends = offset + contentLength;
@ -561,7 +565,7 @@ namespace Esiur.Resource.Template
// start parsing...
var od = new ResourceTemplate();
var od = new TypeTemplate();
od.content = data.Clip(offset, contentLength);
od.templateType = (TemplateType)data[offset++];

View File

@ -53,8 +53,17 @@ namespace Esiur.Resource
static uint resourceCounter = 0;
static KeyList<Guid, ResourceTemplate> templates = new KeyList<Guid, ResourceTemplate>();
static KeyList<Guid, ResourceTemplate> wrapperTemplates = new KeyList<Guid, ResourceTemplate>();
//static KeyList<Guid, TypeTemplate> templates = new KeyList<Guid, TypeTemplate>();
//static KeyList<Guid, TypeTemplate> wrapperTemplates = new KeyList<Guid, TypeTemplate>();
static KeyList<TemplateType, KeyList<Guid, TypeTemplate>> templates
= new KeyList<TemplateType, KeyList<Guid, TypeTemplate>>()
{
[TemplateType.Unspecified] = new KeyList<Guid, TypeTemplate>(),
[TemplateType.Resource] = new KeyList<Guid, TypeTemplate>(),
[TemplateType.Record] = new KeyList<Guid, TypeTemplate>(),
[TemplateType.Wrapper] = new KeyList<Guid, TypeTemplate>(),
};
static bool warehouseIsOpen = false;
@ -124,13 +133,13 @@ namespace Esiur.Resource
var resourceTypes = (Type[])generatedType.GetProperty("Resources").GetValue(null);
foreach (var t in resourceTypes)
{
PutTemplate(new ResourceTemplate(t), true);
PutTemplate(new TypeTemplate(t));
}
var recordTypes = (Type[])generatedType.GetProperty("Records").GetValue(null);
foreach (var t in recordTypes)
{
PutTemplate(new ResourceTemplate(t));
PutTemplate(new TypeTemplate(t));
}
}
}
@ -519,7 +528,7 @@ namespace Esiur.Resource
/// <param name="resource">Resource instance.</param>
/// <param name="store">IStore that manages the resource. Can be null if the resource is a store.</param>
/// <param name="parent">Parent resource. if not presented the store becomes the parent for the resource.</param>
public static async AsyncReply<T> Put<T>(string name, T resource, IStore store = null, IResource parent = null, ResourceTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T:IResource
public static async AsyncReply<T> Put<T>(string name, T resource, IStore store = null, IResource parent = null, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T:IResource
{
if (resource.Instance != null)
throw new Exception("Resource has a store.");
@ -737,15 +746,9 @@ namespace Esiur.Resource
/// Put a resource template in the templates warehouse.
/// </summary>
/// <param name="template">Resource template.</param>
public static void PutTemplate(ResourceTemplate template, bool wrapper = false)
public static void PutTemplate(TypeTemplate template)
{
if (wrapper)
{
if (!wrapperTemplates.ContainsKey(template.ClassId))
wrapperTemplates.Add(template.ClassId, template);
}
else if (!templates.ContainsKey(template.ClassId))
templates.Add(template.ClassId, template);
templates[template.Type][template.ClassId] = template;
}
@ -754,26 +757,31 @@ namespace Esiur.Resource
/// </summary>
/// <param name="type">.Net type.</param>
/// <returns>Resource template.</returns>
public static ResourceTemplate GetTemplateByType(Type type)
public static TypeTemplate GetTemplateByType(Type type)
{
if (!(Codec.ImplementsInterface(type, typeof(IResource))
|| Codec.ImplementsInterface(type, typeof(IRecord))))
return null;
TemplateType templateType = TemplateType.Unspecified;
if (Codec.InheritsClass(type, typeof(DistributedResource)))
templateType = TemplateType.Wrapper;
if (Codec.ImplementsInterface(type, typeof(IResource)))
templateType = TemplateType.Resource;
else if (Codec.ImplementsInterface(type, typeof(IRecord)))
templateType = TemplateType.Record;
else
return null;
var baseType = ResourceProxy.GetBaseType(type);
if (baseType == typeof(IResource)
|| baseType == typeof(IRecord))
return null;
var template = templates[templateType].Values.FirstOrDefault(x => x.DefinedType == type);
// loaded ?
foreach (var t in templates.Values)
if (t.ClassName == baseType.FullName)
return t;
var template = new ResourceTemplate(baseType);
templates.Add(template.ClassId, template);
if (template == null)
template = new TypeTemplate(baseType, true);
return template;
}
@ -783,17 +791,26 @@ namespace Esiur.Resource
/// </summary>
/// <param name="classId">Class Id.</param>
/// <returns>Resource template.</returns>
public static ResourceTemplate GetTemplateByClassId(Guid classId, bool wrapper = false)
public static TypeTemplate GetTemplateByClassId(Guid classId, TemplateType templateType = TemplateType.Unspecified)
{
if (wrapper)
if (templateType == TemplateType.Unspecified)
{
if (wrapperTemplates.ContainsKey(classId))
return wrapperTemplates[classId];
}
else if (templates.ContainsKey(classId))
return templates[classId];
// look in resources
var template = templates[TemplateType.Resource][classId];
if (template != null)
return template;
// look in records
template = templates[TemplateType.Record][classId];
if (template != null)
return template;
return null;
// look in wrappers
template = templates[TemplateType.Wrapper][classId];
return template;
}
else
return templates[templateType][classId];
}
/// <summary>
@ -801,13 +818,28 @@ namespace Esiur.Resource
/// </summary>
/// <param name="className">Class name.</param>
/// <returns>Resource template.</returns>
public static AsyncReply<ResourceTemplate> GetTemplateByClassName(string className)
public static TypeTemplate GetTemplateByClassName(string className, TemplateType templateType = TemplateType.Unspecified)
{
foreach (var t in templates.Values)
if (t.ClassName == className)
return new AsyncReply<ResourceTemplate>(t);
if (templateType == TemplateType.Unspecified)
{
// look in resources
var template = templates[TemplateType.Resource].Values.FirstOrDefault(x => x.ClassName == className);
if (template != null)
return template;
return null;
// look in records
template = templates[TemplateType.Record].Values.FirstOrDefault(x => x.ClassName == className);
if (template != null)
return template;
// look in wrappers
template = templates[TemplateType.Wrapper].Values.FirstOrDefault(x => x.ClassName == className);
return template;
}
else
{
return templates[templateType].Values.FirstOrDefault(x => x.ClassName == className);
}
}
public static bool Remove(IResource resource)