【问题标题】:How to make an enum variable based on classes in project如何根据项目中的类创建枚举变量
【发布时间】:2014-12-06 21:43:48
【问题描述】:

我正在编写一个 DLL,它将公开这样的方法:

public static void Convert(string inputFile, string outputFile, FileType fileType)

目前,FileType 是这样公开的枚举:

public enum FileType
{ 
    ConvertClassOne,
    ConvertClassTwo,
    ConvertClassThree
}

这将表示可以转换给定类型文件的每个类。我将有几个基于接口的不同类,每个类都可以处理特定类型的文件。

我不想像上面那样有一个枚举,每次我添加一个类时我都必须手动更改它,以便调用程序可以告诉我他们给我的文件类型,我想公开一个根据我的项目中具有给定属性的类自动更改自身的枚举。

所以如果我添加一个具有给定属性的类:

[SomeAttribute]
public class NewClassAdded()
{
}

FileType 枚举会选择这个并且调用程序将能够看到

FileType.NewClassAdded

无需我手动更改任何其他内容。我很确定反射将允许我编写一个方法,该方法返回具有给定属性的每个类的名称,但我不确定具体如何,也不知道如何将这些名称公开为枚举。

谢谢,

安德鲁

【问题讨论】:

  • 您几乎可以肯定不能通过反射来做到这一点,因为根据定义,那时代码必须已经编译。您需要某种预构建过程来执行此操作,类似于使用 AOP 实现所做的工作。
  • 正如@Servy 所说,无论如何,您的“转换”例程都必须提前知道每种 FileType 类,才能在开关或 if/else if 块中使用枚举。所以,这种方法肯定不会“那么”有用(即使你设法做你想做的事,我认为即使使用反射也是不可能的(或容易的)。为什么不使用接口来处理“转换”并让每个 FileType 类都实现它,这样你的“转换”例程就不用担心细节了吗?
  • 为什么不创建 T4 模板?检查这篇文章stackoverflow.com/questions/4395000/…
  • @Jauch 这不是问题。他正在编写一个类库。当他将代码添加到他的库时,他希望它自动添加到枚举中。他的库的使用者在编写代码时将使用已经构建的库以及所有实现。我的理解是图书馆的消费者并没有添加他们自己的转换器。
  • 哦,我明白了,@Servy。在这种情况下,我不认为这样做的效用可以支付为此付出的努力。无论如何,假设目标是“定义”正确的转换方法,通过使用枚举,我认为最好改为使用接口,或者可能是带有一些虚拟方法的基类,并使代码通用和与 FileType 不同实现的数量无关。

标签: c# reflection enums attributes


【解决方案1】:

这可能不是您要寻找的答案,但您是否考虑过使用泛型?它将解决您可以添加新功能的问题。您可以使用代表您的枚举的接口。对于每个枚举值,都会有一个实现该接口的类。每当你想添加一个新选项时,只需添加一个实现接口的新类。您可以在这些类中添加额外的功能,或者您可以将它们用作枚举值的替代品(下面代码中的变体 1 和 2)。示例:

class Program
{
    static void Main(string[] args)
    {
        Converter.Convert("input", "output", new FormatA());
        Converter.Convert("input", "output", new FormatB());
    }
}

class Converter
{
    public static void Convert<T>(string inputFile, string outputFile, T formatter) where T : IConvertFormat
    {
        // First variant: Keep the functionality in the formatter object

        formatter.DoSomething(inputFile, outputFile);

        // Second variant: check for the actual type

        if (formatter is FormatA)
        {
            // ... do format A
        }
        else if (formatter is FormatB)
        {
            // ... do format B
        }
    }
}

interface IConvertFormat
{
    // Method not required for variant 2
    void DoSomething(string inputFile, string outputFile);
}

class FormatA : IConvertFormat
{
    public void DoSomething(string inputFile, string outputFile)
    {
        // .. do it like Format A (not required for variant 2)
    }
}

class FormatB : IConvertFormat
{
    public void DoSomething(string inputFile, string outputFile)
    {
        // do it like Format B (not required for variant 2)
    }
}

PS。我认为这基本上就是@Jauch 的提议。

【讨论】:

  • 差不多,@Izydrmr。有其他方法,但我找到了一个优雅的方法。
  • 但是调用程序不需要知道“FormatA”和“FormatB”的存在吗?枚举的全部原因是它们显示了所有选择,并且不必知道要传递的实际类名。
  • 我不确定您所说的“调用程序必须知道”是什么意思。你的意思是,程序员知道,还是你的意思是,程序可以查询选项,例如将它们显示给用户?确实,您可以轻松地枚举枚举。但是,提供一个枚举所有有效类的库方法也很容易。
【解决方案2】:

根据讨论,我会给你以下想法,@Starfleet。 首先,创建一个带有“转换”功能和“描述”属性的接口。

interface IFileConversion
{
    bool Convert (string inputFile, string outputFile);
    string Description { get; }
}

把这个接口放在一个dll上,任何想实现它的类都可以引用它。

然后,您可以在您拥有的任何“FileType”类上实现此接口。 在您的库中,您可以创建一个函数来返回所有实现 IFileConversion 的类(通过反射非常简单)。

类似:

static class Info
{
    public static List<IFileConversion> AvailableConversions ()
    {
       //Code to retrieve the available classes that implement IFileConversion
    }
}

这样,如果您想“枚举”库中的可用类(并通过某种可视化界面将它们显示给用户),只需调用 Info.AvailableConversions。 他们使用“description”属性向用户显示可用的转化。

但是,如果情况并非如此,并且您只想让其他开发人员知道可用的转换类是什么,那么最好通过文档。如果您使用“///”,您可以提供通常显示在大多数 UIDev 代码完成中的信息和描述。在这种情况下,您可以创建一个特定的命名空间,例如:

namespace FileConversion
{
     //Put all conversion classes under this namespace
}

只需键入“FileConversion”即可轻松查看可用的内容。并遍历将出现的列表(以及您提供的额外信息)。

使用 IFileConversion 接口的优点是您的合作伙伴(其他开发人员)不必担心对类的任何了解。他们只是选择了他们想要的(通过描述或文档)并调用转换例程。

在任何情况下,这两种解决方案都比枚举描述符更好,更具描述性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    相关资源
    最近更新 更多