c# - Activator.CreateInstance 在运行时强制转换为类型
问题描述
我正在编写一个使用大量反射的小型框架,并且我想将我的代码分成多个项目以获得更好的可维护性。
主项目包含一个静态反射缓存,我在其中扫描所有程序集的某些类型并缓存这些结果以供将来在处理属性时使用。
这个缓存会根据在类上找到的属性类型生成一堆不同的属性上下文。IE。
PropertyAttributeContext -> 应用于类/属性的通用属性 XmlPropertyAttributeContext -> 应用于类/属性的 xml 特定属性 JsonPropertyAttributeContext -> 应用于类/属性的 json 特定属性
这些类型未在主项目中定义。我想要做的是,如果用户加载 JsonProject,该项目将自动注册自身并将其类型添加到缓存中。这样,当缓存被初始化时,所有注册的类型都会被加载。具体类型都从同一个抽象基类扩展而来。
我找不到使用泛型的方法,因为它需要声明和迭代未绑定的 ConcurrentBag 这是不可能的。
即这不起作用:
public class MetaDataEntry<I,T>
{
public I Interface { get; set; }
public T Type { get; set; }
}
class MetaDataRegistry
{
// OOPS
public static ConcurrentBag<MetaDataEntry<,>> Entries = new ConcurrentBag<MetaDataEntry<,>>();
public void Register<I, T>()
{
Entries.Add(new MetaDataEntry<I,T>());
}
}
所以看起来我仅限于使用 typeof 和 Activator.CreateInstance 来实例化我的类型。我遇到的问题是我无法将创建的对象转换为它的派生类型。您可以在下面看到我正在存储键类型的 ConcurrentDictionary 和派生实例的 AbstractAttributeContext。
using ConcurrentDictionaryTypeContext = System.Collections.Concurrent.ConcurrentDictionary<System.Type, Integration.Cache.Context.AbstractAttributeContext>;
public class ClassMetaData
{
private ConcurrentDictionary<PropertyInfo, ConcurrentDictionaryTypeContext> _propertyContexts;
private ClassAttributeContext _classAttributeContext;
private Type _classType;
private PropertyInfo[] _properties;
public ClassMetaData(Type type)
{
_classType = type;
_classAttributeContext = new ClassAttributeContext(type);
_properties = type.GetProperties(ReflectionUtils.GetPublicBindingFlags());
_propertyContexts = new ConcurrentDictionary<PropertyInfo, ConcurrentDictionaryTypeContext>();
foreach (PropertyInfo property in _properties)
{
ConcurrentDictionaryTypeContext propertyDictionary = new ConcurrentDictionaryTypeContext();
foreach(MetaDataEntry entry in MetaDataRegistry.Entries)
{
if (ReflectionUtils.HasCustomAttributeType(entry.Interface, property))
// ****** CANNOT CAST THIS TO CONCRETE TYPE ********
if (!propertyDictionary.TryAdd(entry.Type, Activator.CreateInstance(entry.Type, new object[]{ property })))
throw new ReflectionCacheException("Type " + type.AssemblyQualifiedName + " could not be added to the cache because property " + property.Name + " could not be added to cache");
}
if (!_propertyContexts.TryAdd(property, propertyDictionary))
throw new ReflectionCacheException("Type " + type.AssemblyQualifiedName + " could not be added to the cache");
}
}
public Type Type { get { return _classType; } }
public PropertyInfo[] Properties { get { return _properties; } }
public ClassAttributeContext ClassAttributeContext { get { return _classAttributeContext; } }
public AttributeContextType GetAttributeContextForProperty<AttributeContextType>(PropertyInfo property) where AttributeContextType : AbstractAttributeContext
{
return (AttributeContextType)_propertyContexts[property][typeof(AttributeContextType)];
}
public bool HasPropertyAttributeContext<AttributeContextType>(PropertyInfo property)
{
return _propertyContexts.ContainsKey(property) && _propertyContexts[property].ContainsKey(typeof(AttributeContextType));
}
public ConcurrentDictionaryTypeContext GetContextsForProperty(PropertyInfo property)
{
return _propertyContexts[property];
}
}
public class MetaDataCache
{
private static ConcurrentDictionary<Type, ClassMetaData> _classes = Initialize();
private static ConcurrentDictionary<Type, ClassMetaData> Initialize()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
var keyValuePairs = assemblies.Select((Assembly assembly) =>
{
var qq = assembly.GetTypes()
.Where((Type type) =>
{
return type.GetProperties(ReflectionUtils.GetPublicBindingFlags())
.Any((PropertyInfo property) => property.GetCustomAttributes(typeof(IAttributeMarker), true).Length > 0);
})
.Select((Type type) => new KeyValuePair<Type, ClassMetaData>(type, new ClassMetaData(type)));
return qq;
});
return new ConcurrentDictionary<Type, ClassMetaData>(keyValuePairs.SelectMany(i => i));
}
public static ClassMetaData Get<T>()
{
return Get(typeof(T));
}
public static ClassMetaData Get(Type type)
{
if (_classes.ContainsKey(type))
return _classes[type];
else
{
// TODO: Include search for class level attributes
if (ReflectionUtils.GetCustomAttributesForAllProperties<IAttributeMarker>(type).Length > 0)
{
if (!_classes.TryAdd(type, new ClassMetaData(type)))
throw new ReflectionCacheException("Type " + type.AssemblyQualifiedName + " could not be added to the cache");
else
return _classes[type];
}
else
throw new InvalidTypeException("Type " + type.AssemblyQualifiedName + " does not have any attributes applied to the class");
}
}
public static bool Contains(Type type)
{
return _classes.ContainsKey(type);
}
}
public class MetaDataEntry
{
public Type Interface { get; set; }
public Type Type { get; set; }
}
class MetaDataRegistry
{
public static ConcurrentBag<MetaDataEntry> Entries = new ConcurrentBag<MetaDataEntry>();
public void Register(Type interface_, Type type)
{
Entries.Add(new MetaDataEntry() { Interface = interface_, Type = type });
}
public void Register<I, T>()
{
Entries.Add(new MetaDataEntry() { Interface = typeof(I), Type = typeof(T) });
}
}
当然这一定可以实现吗?
解决方案
推荐阅读
- http - 如何将 JSON 对象发布到实时网站
- python - 我如何检查几乎所有行是否相同,如果是,则验证最后不同的行是否有一些常数 k
- android - 如果特定文本没有在android中的单行中调整,如何在下一行中移动文本
- javascript - How to create an image in Node js?
- php - phpinfo() 没有更新到终端版本?
- android - Room db:数据库问题
- php - 当括号内的字母时,定制的 ucwords 失败
- r - 在 R 中转换数据对象
- javascript - 如何处理 Sequelize 嵌套/复合查询?
- r - 如何使用“by”在 data.table 中应用自定义函数并选择某些列