1

I'm writing a DLL that will expose a method like this:

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

At the moment, FileType is an enum that is exposed like this:

public enum FileType
{ 
    ConvertClassOne,
    ConvertClassTwo,
    ConvertClassThree
}

This will represent each class that can convert a given type of file. I'll have several different classes based on an interface, each of which can process a particular type of file.

Instead of having an enum like I have above, where I have to change it manually each time I add a class so that the calling program can tell me which file type they're giving me, I'd like to expose an enum that automatically changes itself based on the classes in my project that have a given attribute.

So if I add a class with a given attribute:

[SomeAttribute]
public class NewClassAdded()
{
}

the FileType enum will pick this up and the calling program will be able to see

FileType.NewClassAdded

without me having to change anything else by hand. I'm pretty sure that Reflection will allow me to write a method that returns the name of each class with the given attribute, but I'm not sure exactly how, nor do I know how I would then expose these names as an enum.

Thanks,

Andrew

Starfleet Security
  • 1,813
  • 3
  • 25
  • 31
  • You're almost certainly not going to be able to do this through reflection, because, by definition, the code would have to already have been compiled by then. You'll need some sort of pre-build process to do this, similar to what's done with AOP implementations. – Servy Dec 05 '14 at 16:47
  • 1
    As @Servy said, your "Convert" routine would have to know in advance every kind of FileType class anyway, to use the enumeration in a switch or if/else if block. So, this approach for sure will not be "that" useful (even if you manage to do what you want, what I think is not possible (or easy) even with reflaction. Why not using an interface to deal with the "conversion" and make every FileType class implement it, so your "Convert" routine do not have to worry about the details? – Jauch Dec 05 '14 at 16:51
  • why don't you create a T4 template? check this post http://stackoverflow.com/questions/4395000/t4-template-to-generate-enums – maruthu chandrasekaran Dec 05 '14 at 16:52
  • 1
    @Jauch That wouldn't be an issue. He's writing a class library. When he adds code to his library, he wants it to be automatically added to the enum. Consumers of his library will be using an already built library with all of the implementations when writing their code. My understanding is that consumers of the library aren't adding their own converters. – Servy Dec 05 '14 at 16:53
  • Oh, I see, @Servy. In this case, I don't think the utility of this to pay for the effort to make this. In any case, assuming that the goal is to "define" the right conversion method, through the use of enums, I think it is much better instead use interfaces, or mayba a base class with some virtual methods, and make the code generic and independent of the number of different implementations of FileType. – Jauch Dec 05 '14 at 16:59
  • @Servy is correct, I'm just trying to expose an enum to outsiders, but I was hoping to make it a little easier on myself by not having to manually update the enum every time I add a class. Not sure the ROI will be enough though, since by definition I'll be in there changing code anyway. :) – Starfleet Security Dec 05 '14 at 17:08
  • If the idea is to expose something to others to use, the idea ia even worse. Every time you update you list, every app that uses your library will have to be updated or will have to use a particular versipn of the lib – Jauch Dec 05 '14 at 18:11
  • The best in this case is still to use public standard interfaces and allow new functionality to be added without disrupting code that already uses the lib. – Jauch Dec 05 '14 at 18:13
  • @Jauch-- No, this would only be an enum, and I wouldn't be removing any existing classes. So anything that was already out there using one of the enum values would always work. The signature of the method itself doesn't change. – Starfleet Security Dec 05 '14 at 18:21
  • Hum... Ok. In any case, I dont thinknis a good approach. What are you trying to acomplish exactly? I mean, what is the idea of your lib? – Jauch Dec 05 '14 at 18:27
  • It's just an internal library we'd be using in-house to allow us to convert files from one format into a standard format we use for another area. I was just trying to avoid a (small) extra step and was curious to know how to do the automated enum thing because I thought it was possible. Thanks for all the responses, but it sounds like I either can't do it, or it's not worth the tiny bit it'll save me anyway. – Starfleet Security Dec 05 '14 at 19:09
  • Your primary problem is that you're relying on an `enum` so that you can do a `switch` or something similar. Rather than the `enum`, pass a converter function (or interface) similar to what lzydrmr recommends in his answer. – Jim Mischel Dec 05 '14 at 19:31
  • Yeah... As was told, using generics can really give you much more flexibility. Personally I implemented a "plugin" framework that allows me to add functionality without having to worry (too much) with old code. One of the things I do is exactly this: format conversion. With plugins this is really easy – Jauch Dec 05 '14 at 20:08
  • @StarfleetSecurity, None of the answers solved your problem? If yes, mark it as the solution. And upvote the ones that were useful in your opinion. Thanks :) – Jauch Dec 07 '14 at 20:27

2 Answers2

2

This may not be the answer you are looking for, but have you considered using generics? It would solve the problem that you can add new functionality. You could use an interface that represents your enum. For each enum value, there would be a class that implements that interface. Whenever you want to add a new option, just add a new class implementing the interface. You can put additional functionality in these classes, or you could just use them as substitutes for enum values (variant 1 and 2 in the code below). Example:

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. I think that is basically what @Jauch is proposing.

lzydrmr
  • 867
  • 5
  • 7
  • Pretty much, @Izydrmr. There are ither ways but this I found an elegant one. – Jauch Dec 05 '14 at 20:05
  • But then doesn't the calling program have to know about the existence of "FormatA" and "FormatB"? The whole reason for the enum is so they are shown all the choices and don't have to know the actual class name to pass. – Starfleet Security Dec 05 '14 at 21:04
  • I am not sure what you mean by 'the calling program have to know'. Do you mean, the programmer knows, or do you mean, the program can query the options and e.g. display them to a user? It is true that you can enumerate enum's easily. However, it would also be easy to provide a library method that enumerates all valid classes. – lzydrmr Dec 05 '14 at 21:49
1

Based on the discussions, I'll give you the following idea, @Starfleet. First, create an interface with a "conversion" function and a "description" property.

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

Put this interfaces on a dll, and any class that wants to implement it can reference it.

Then, you can implement this interface on any "FileType" class you have. In your library you can create a function to return all classes that implement IFileConversion (through reflection is pretty easy).

Something like:

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

This way, if you want to "enumerate" the available classes in your library (and show them to a user through some kind of visual interface), just call Info.AvailableConversions. And them show to the user the available conversions using the "description" property.

But, if this is not the case and what you want is simply to other developers to know what are the available conversion classes, the better is through documentation. If you use the "///" you can give information and description that usually shows up on code completion in most UIDev. In this case, you can create a particular namespace, like:

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

And it's easy to see the available just typing "FileConversion." and iterating through the list that will appear (with the extra information you gave).

The advantage of using the IFileConversion interface is that your partners (other developers) do not have to worry about known anything about the class. They just chose the one they want (through the description or documentation) and call the Conversion routine.

In any case those two solutions are better and much more descriptive than just the enumeration descriptor.

Jauch
  • 1,500
  • 9
  • 19