创建基类方法的更好方法,该方法依赖于子类中的大量类型参数值
本文关键字:方法 子类 类型参数 类方法 基类 更好 创建 依赖于 | 更新日期: 2023-09-27 18:33:59
我有一个抽象基类HandlerProvider,其中包含(很多(泛型类型参数。这些参数用于确定(使用反射(哪些类从指定接口继承,并具有指定类型的自定义属性,该属性包含另一种类型的枚举值。(所有类型都在类型参数中指定。
接下来,我有两个子类 TriggerHandlerProvider 和 ActionHandlerProvider,它们实现抽象类,并使用在抽象类中初始化的 ClassType 字典。
我的问题是:有没有更好(更优雅(的OOP方法来确定ClassType字典(至少摆脱一些类型参数(,而不必在每个子类中复制DetermineTypesToHandle的代码?
代码如下。
public interface IAttribute<out TEnum>
{
TEnum GetValue();
}
public abstract class HandlerProvider<THandlerInterface, TInterface, TAttribute, TTypeEnum> : IHandlerProvider
where TAttribute : Attribute, IAttribute<TTypeEnum>
{
// Maps enum values to System.Type instances.
protected readonly Dictionary<TTypeEnum, Type> ClassTypes;
protected HandlerProvider(List<TTypeEnum> typeIds)
{
ClassTypes = new Dictionary<TTypeEnum, Type>();
DetermineTypesToHandle(typeIds);
}
private void DetermineTypesToHandle(List<TTypeEnum> typeIds)
{
if (typeIds == null)
{
throw new ArgumentNullException();
}
IEnumerable<Type> classes = GetTypesWithAttribute(Assembly.GetExecutingAssembly());
if (classes == null) return;
foreach (Type classType in classes)
{
if (typeof(TInterface).IsAssignableFrom(classType))
{
TAttribute attribute = GetTypeAttribute(classType);
TTypeEnum attributeValue = attribute != null ? attribute.GetValue() : default(TTypeEnum);
if (!Equals(attributeValue, default(TTypeEnum)) && typeIds.Exists(tt => Equals(tt, attributeValue)))
{
ClassTypes.Add(attributeValue, classType);
}
}
}
}
private TAttribute GetTypeAttribute(Type classType)
{
return Attribute.GetCustomAttribute(classType, typeof(TAttribute)) as TAttribute;
}
private IEnumerable<Type> GetTypesWithAttribute(Assembly assembly)
{
return from t in assembly.GetTypes()
where t.IsDefined(typeof(TAttribute), false)
select t;
}
}
public class TriggerHandlerProvider : HandlerProvider<ITriggerHandler, ITrigger, TriggerTypeAttribute, ETriggerType>
{
public TriggerHandlerProvider(List<ETriggerType> typeIds)
: base(typeIds)
{
// Use the ClassTypes property from the base class to create a new TriggerHandler.
}
}
public class ActionHandlerProvider : HandlerProvider<IActionHandler, IAction, ActionTypeAttribute, EActionType>
{
public ActionHandlerProvider(List<EActionType> typeIds)
: base(typeIds)
{
// Use the ClassTypes property from the base class to create a new ActionHandler.
}
}
@Jeroen,我建议你简化。
使用以下架构,只需要在将保存特定处理程序的代码的类上有一个属性(枚举值(。
每个特定的处理程序都必须实现一个接口,即它与"更高级别"处理程序提供程序(例如,您的 ActionHandlerProvider(的连接。
我将代码用于填充处理程序集合放在静态类中,因为这对我来说似乎更自然,但很容易使其再次成为"基类"。在任何情况下,您只需要两个参数,一个模板和一个接口即可工作。
该接口可以保存可以以标准方式传递给特定处理程序的常用方法和数据,因此处理程序提供程序不必担心每个处理程序的特殊性(无论如何,在 modt 的情况下(
波纹管是带有示例的代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace ConsoleApplication3
{
[System.AttributeUsage(System.AttributeTargets.Class)]
public class HandlerAttribute : Attribute
{
protected string fType;
public HandlerAttribute(string type)
{
fType = type;
}
public string HandlerType
{
get { return fType; }
set { fType = value; }
}
}
public interface IHandlerA
{
//commom interface for handlers of type HandlerA
string Name { get; }
}
public enum EHandlerATypes
{
A,
B
}
[HandlerAttribute("A")]
public class SpecificHandlerATypeA : IHandlerA
{
public string Name
{
get { return "HandlerA type A"; }
}
}
[HandlerAttribute("B")]
public class SpecificHandlerATypeB : IHandlerA
{
public string Name
{
get { return "HandlerA type B"; }
}
}
public class HandlerA
{
public Dictionary<EHandlerATypes, Type> fHandlerACollection;
public HandlerA()
{
fHandlerACollection = HandlerSearchEngine.GetHandlersList<EHandlerATypes, IHandlerA>(new Assembly[] { this.GetType().Assembly });
}
}
public static class HandlerSearchEngine
{
public static Dictionary<TEnum, Type> GetHandlersList<TEnum, THandler>(Assembly[] assemblyList)
{
if (!typeof(TEnum).IsEnum)
throw new Exception("Invalid parameter TEnum");
Dictionary<TEnum, Type> dic = new Dictionary<TEnum, Type>();
foreach(Assembly assembly in assemblyList)
{
var types = assembly.GetTypes().Where(t => t.IsClass && typeof(THandler).IsAssignableFrom(t));
foreach(Type type in types)
{
HandlerAttribute ha = type.GetCustomAttribute<HandlerAttribute>();
TEnum handlerType = (TEnum) Enum.Parse(typeof(TEnum), ha.HandlerType, true);
if (dic.ContainsKey(handlerType))
throw new Exception("One handler with the same handler type already exists in the collection");
dic[handlerType] = type;
}
}
return dic;
}
}
class Program
{
static void Main(string[] args)
{
HandlerA a = new HandlerA();
foreach(KeyValuePair<EHandlerATypes, Type> pair in a.fHandlerACollection)
{
IHandlerA ha = (IHandlerA)Activator.CreateInstance(pair.Value);
Console.WriteLine(ha.Name);
}
Console.ReadKey();
}
}
}
此示例的输出将是:
HandlerA type A
HandlerA type B
希望这可以帮助您简化事情。