【问题标题】:How to search a class within a namespace by the value of an attribute and return an object?如何通过属性的值搜索命名空间内的类并返回一个对象?
【发布时间】:2016-03-31 10:03:21
【问题描述】:

我需要创建一个包含各种对象的工厂。尽可能抽象。能够通过参数从过去的条件创建各种对象,但不知道具体的类。

我想通过将枚举的值传递给工厂来做到这一点,它必须能够通过反射来查找命名空间中的所有类,这些类使用的属性值与最后一个参数相同。

我留下以下代码 sn-ps 作为参考。

具体类的一个例子:

[Batatinha(SaborCode.Churrasco)]
internal class BatatinhaChurrasco : AbstractBatatinha
{
    public override string Sabor
    {
        get { return "Churrasco"; }
    }
}

这个工厂的一个例子:

internal class BatatinhaFactory
{
    internal AbstractBatatinha GetBatatinha(SaborCode sabor)
    {
        // Some logic ... possibly using reflection.
    }
}

所需调用的示例:

AbstractBatatinha batatinha = new BatatinhaFactory().GetBatatinha(SaborCode.Churrasco);
Console.WriteLine(batatinha.Sabor);
// ==> "Churrasco"

Obs.:库应该是可移植的。 (.NET Framework 4.0.3、Silverlight 5、Windows 8、Windows Phone 8.1、Windows Phone Silverlight 8)

简而言之:给定一个枚举的值,如何使用反射检索将参数作为属性的类的类型?

【问题讨论】:

  • 你有什么问题?
  • 给定一个枚举的值,如何通过反射获取使用参数作为属性的类的类型?
  • 这非常接近你想要的:stackoverflow.com/a/4387761

标签: c# linq reflection system.reflection


【解决方案1】:

我想我明白你想要做什么。我编写了自己的课程并对此进行了测试:

public enum AttributeTypes
{
    TypeA, TypeB
}

public class ReferencesEnumAttribute : Attribute
{
    public AttributeTypes AttributeType { get; set; }

    public ReferencesEnumAttribute(AttributeTypes attributeType)
    {
        AttributeType = attributeType;
    }
}

public class FindsClassesByAttributeAndEnumValue
{
    public Type[] FindClassesInAssemblyContaining<T>(AttributeTypes attributeType)
    {
        return typeof (T).Assembly.GetTypes()
            .Where(type => type.GetCustomAttributes(false)
                .Any(attribute => attribute is ReferencesEnumAttribute
                  && ((ReferencesEnumAttribute) attribute).AttributeType == attributeType))
            .ToArray();

    }
}

然后是几个有属性的类:

[ReferencesEnum(AttributeTypes.TypeA)]
public class HasAttribute {}

[ReferencesEnum(AttributeTypes.TypeA)]
public class AlsoHasAttribute{}

[ReferencesEnum(AttributeTypes.TypeB)]
public class DoesntHaveAttribute {}

最后是单元测试:

[TestMethod]
public void GetClassesWithAttribute()
{
    var finder = new FindsClassesByAttributeAndEnumValue();
    var types = finder.FindClassesInAssemblyContaining<ReferencesEnumAttribute>(AttributeTypes.TypeA);
    Assert.AreEqual(2, types.Length);
}

您还可以更进一步,对其施加约束,以便您仅返回从类型继承或实现接口的类型。否则你可能会得到除了属性之外没有任何共同点的类型。

public class FindsClassesByAttributeAndEnumValue
{
    public Type[] FindClassesInAssemblyContaining<TContains,TInheritsFrom>(AttributeTypes attributeType)
        where TInheritsFrom : class
    {
        return typeof (TContains).Assembly.GetTypes()
            .Where(type => 
                type.IsAssignableFrom(typeof(TInheritsFrom))
                && type.GetCustomAttributes(false)
                .Any(attribute => attribute is ReferencesEnumAttribute
                                  && ((ReferencesEnumAttribute) attribute).AttributeType == attributeType))
            .ToArray();

    }
}

【讨论】:

    【解决方案2】:

    不建议在工厂类中使用反射,因为它可能会导致代码性能问题。在代码中的某处使用反射,您将不得不使用 Activator.CreateInstance() 方法,这会导致您的应用出现性能问题,请查看这篇文章:Does System.Activator.CreateInstance(T) have performance issues big enough to discourage us from using it casually?

    【讨论】:

    • 它还限制工厂使用默认构造函数创建类型。我只是按照要求解决问题,因为它听起来很有趣。但我会使用 DI 容器而不依赖于属性。
    • 我关心的是性能问题。正如@ScottHannen 所建议的,我可能会用 DI 找到一些解决方案。有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 1970-01-01
    • 2013-01-15
    • 2015-05-01
    • 1970-01-01
    • 2020-05-28
    • 2021-10-18
    相关资源
    最近更新 更多