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
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.
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.
Related
For the purposes of this question, a 'constant reference' is a reference to an object from which you cannot call methods that modify the object or modify it's properties.
I want something like this:
Const<User> user = provider.GetUser(); // Gets a constant reference to an "User" object
var name = user.GetName(); // Ok. Doesn't modify the object
user.SetName("New value"); // <- Error. Shouldn't be able to modify the object
Ideally, I would mark with a custom attribute (e.g. [Constant]) every method of a class that doesn't modify the instance, and only those methods can be called from the constant reference. Calls to other methods would result in an error, if possible, during compile time.
The idea is I can return a read-only reference to and be sure that it will not be modified by the client.
The technique you're referring to is called "const-correctness" which is a language feature of C++ and Swift, but not C#, unfortunately - however you're onto something by using a custom attribute because that way you can enforce it via a Roslyn extension - but that's a rabbit-hole.
Alternatively, there's a much simpler solution using interfaces: because C# (and I think the CLR too) does not support const-correctness (the closest we have is the readonly field modifier) the .NET base-class-library designers added "read-only interfaces" to common mutable types to allow a object (wheather mutable or immutable) to expose its functionality via an interface that only exposes immutable operations. Some examples include IReadOnlyList<T>, IReadOnlyCollection<T>, IReadOnlyDictionary<T> - while these are all enumerable types the technique is good for singular objects too.
This design has the advantage of working in any language that supports interfaces but not const-correctness.
For each type (class, struct, etc) in your project that needs to expose data without risk of being changed - or any immutable operations then create an immutable interface.
Modify your consuming code to use these interfaces instead of the concrete type.
Like so:
Supposing we have a mutable class User and a consuming service:
public class User
{
public String UserName { get; set; }
public Byte[] PasswordHash { get; set; }
public Byte[] PasswordSalt { get; set; }
public Boolean ValidatePassword(String inputPassword)
{
Hash[] inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
return Crypto.CompareHashes( this.PasswordHash, inputHash );
}
public void ResetSalt()
{
this.PasswordSalt = Crypto.GetRandomBytes( 16 );
}
}
public static void DoReadOnlyStuffWithUser( User user )
{
...
}
public static void WriteStuffToUser( User user )
{
...
}
Then make an immutable interface:
public interface IReadOnlyUser
{
// Note that the interfaces' properties lack setters.
String UserName { get; }
IReadOnlyList<Byte> PasswordHash { get; }
IReadOnlyList<Byte> PasswordSalt { get; }
// ValidatePassword does not mutate state so it's exposed
Boolean ValidatePassword(String inputPassword);
// But ResetSalt is not exposed because it mutates instance state
}
Then modify your User class and consumers:
public class User : IReadOnlyUser
{
// (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}
public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
...
}
// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
...
}
So, these are the first two ideas I initially had, but don't quite solve the problem.
Using Dynamic Objects:
The first idea I had was creating a Dynamic Object that would intercept all member invokations and throw an error if the method being called isn't marked with a [Constant] custom attribute. This approach is problematic because a) We don't have the support of the compiler to check for errors in the code (i.e. method name typos) when dealing with dynamic objects, which might lead to a lot of runtime errors; and b) I intend to use this a lot, and searching for method names by name every time a method is called might have considerable performance impact.
Using RealProxy:
My second idea was using a RealProxy to wrap the real object and validate the methods being called, but this only works with objects that inherit from MarshalByRefObject.
We have a large class that contains a bunch of css selectors stored as static strings. Example:
public class Constants
}
public static string Selector1 = "#someID";
public static string Selector2 = ".some.classes a";
// and so on...
}
We now need to test a different version of our web app which requires a few different selectors. So we need to find a clean scalable way to override these selectors based on some configuration.
My solution to the problem is this: I'm trying to create a BaseConstants class which will have the current set of selectors. Then I create another class called UpdatedConstants which will subclass the BaseConstants class. This class will then contian all the selectors and just override the ones that need changing with the new keyword. Example:
public class UpdatedConstants : BaseConstants
{
// Overrides the base class's Selector1 string
public new static string Selector1 = "#someOtherID";
}
This works well for overriding the strings however I'm stumped as to how the project will decide which static class to use when it is compiled. All our existing code uses the Constants class like this:
var element = driver.GetElement(Constants.SomeSelector);
Is there a way to dynamically decide which class is the final Constants class? Perhaps by some meta-programming magic?
Let me know if anyone has questions or needs a better explanation of the problem. Thanks
Make your constants classes non-static and use a singleton. This also lets you use virtual properties, since you want to use a base Constants class.
public static class Constants
{
static Constants()
{
#if FOO
Current = new ConstantsFoo();
#elif BAR
Current = new ConstantsBar();
#endif
}
public static ConstantsBase Current { get; private set; }
}
//...snip
var element = driver.GetElement(Constants.Current.SomeSelector);
If you don't want to change all occurences Constants.SomeSelector, the only way to have different behavoirs is using pre-processor directives in the Constants class:
public class Constants
}
#if OLD
public static string Selector1 = "#someID";
#elif NEW
public static string Selector1 = "#someNewID";
#endif
public static string Selector2 = ".some.classes a";
// and so on...
}
Else you can use the approach from Ed Plunketts answer.
Okay, probably not what you're looking for, but... You might want to consider not doing it like this.
Put it this way - if you travel down the road, what will your code look like in 5 years? You'll have a base class that contains your original settings, a subclass for how they were modified the first time (when you asked this question), a subclass inheriting from that subclass on how they were modified the next time, and so on. I could easily imagine 10 subclasses in a giant chain - and if you wanted to trace the current value for any setting, you'd have to travel up that chain until you found where it was most recently set/overriden. It sounds like a maintenance nightmare, to be honest.
If I were in your shoes, this is what the new code would look like:
public static class Constants
{
public static string Selector1 { get { return ReadFromSettings("Selector1"); } }
public static string Selector2 { get { return ReadFromSettings("Selector2"); } }
//etc
// then, code for ReadFromSettings()
}
... and then migrate those settings into an actual settings file. Nobody needs to change any code on the calling end (they still reference Constants.Selector1) - except, instead of having this all hard-coded in a series of derived classes, you just have a file with your values.
I'd like to discuss about the best approach (in C#) to instantiate an object based on an input string. Let me explain.
Let'say I have a base class:
public abstract class BaseCar
{
public asbtract int GetEngineID();
//Other stuff...
}
Then I have several implementations of this class, let's say:
public class SportCar : BaseCar
{
public override int GetEngine()
{
//Specific implementation
}
}
public class OtherCar: BaseCar
{
public override int GetEngine()
{
//Specific implementation
}
}
And so on...
What I'd like to do is to make a static CarFactory class which has a CreateCar method which accepts a string as a parameter and returns a BaseCar instance, depending on what string you give. The string would be a name of a child class.
For example, if I call CarFactory.CreateCar('SportCar') it should return a SportCar instance.
I know I could use a simple switch statement to check which car has been requested and create a new instance based on that but I don't like this approach for two reasons:
I plan to have a lot of child classes, hard-coding every case wouldn't be too easy to mantain
I plan to implement an inizialization procedure to also give some initial values to the objects I create (using Reflection), so mixing hard-coding and reflection doesn't seem to be a good idea for me.
What I was thinking about is to use the Assembly.CreateInstance from System.Reflection to create an instance of the specified class but since this is the first time I approach this problem, I don't know if there are better ways to do that. Is this a valid approach ?
Considering the input string will come from an XML file, is there a simplier method ? Maybe my issue is already handled in some .NET Assembly which I'm missing.
Here is what I came up with. A generic factory class that automatically registers all types that are a subclass of the given type, and allows you to instantiate them via their name. This is somewhat related to the approach shown in the Java SO question linked by #Achilles in the comments, only that there is no initialisation function associated with the type.
There is no need to maintain an enum/switch combination of all types. It should also be somewhat easily extendable to handle your proposed reflection based initialisation.
static class StringFactory<T> where T : class
{
static private Dictionary<string, Type> s_dKnownTypes = new Dictionary<string, Type>();
static StringFactory()
{
RegisterAll();
}
static private void RegisterAll()
{
var baseType = typeof(T);
foreach (var domainAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in domainAssembly.GetTypes()
.Where(t => t.IsSubclassOf(baseType)))
{
s_dKnownTypes.Add(type.Name, type);
}
}
}
static public T Create(string _sTypeName)
{
Type knownType;
if (s_dKnownTypes.TryGetValue(_sTypeName, out knownType))
{
return (T)Activator.CreateInstance(knownType);
}
throw new KeyNotFoundException();
}
}
Assuming the classes of your question exist, you would instantiate a specific car like this:
var car = StringFactory<BaseCar>.Create("SportsCar");
DoSomethingWith(car.EngineID());
Since your question was for a discussion about the best approaches, please consider this only one of them. I have not used this in a production environment, and it is entirely possible that it is the wrong approach to your specific situation. It works well enough to show the general principle, however, and should provide a starting point for further discussion.
I'm making a change to an API that serves data (this is an update to my original question). Some of the searches require data about an author and take a IAuthor object. The API has an IAuthor interface and a single concrete class that implements IAuthor called Author.
I need to change the behaviour of the Search.GetBooksByAuthor method to give different semantic when the author is flagged as a novelist. I've heard about the open/closed principle and it would seem that changing the IAuthor and/or Author and/or Search classes would violate this (the Book class is definitely remaining unchanged, though). How then to make this simple change?
For example, I was originally thinking something like this but my thinking is probably wonky because it involves changing the Search class:
//Before
class Search
{
public Books[] GetBooks(IAuthor author){
// Call data access GetBooks...
}
}
//After
class Search
{
public Books[] GetBooks(IAuthor author){
// To maintain pre-existing behaviour
// call data access GetBooks method with SQL param #AsNovelist = false...
// (or don't pass anything because the SQL param defaults to false)
}
public Books[] GetBooksAsNovelist(IAuthor author){
// To get new behaviour
// call data access GetBooks method with SQL param #AsNovelist = true
// so that their non-fiction books are omitted from results
}
}
It may seem obvious that something has to change to cater for knowing whether or not your author is a Novelist, you could do this one of two ways. You don't have to change anything in theory, you do however need a new class.
public class Novelist : Author, IAuthor { }
Then you can pass a novelist into your method and then deterimne your type of author.
class Search
{
public Books[] GetBooks(IAuthor author){
if(author is Novelist)
//Do some stuff or set a flag/bool value
}
}
OR as previously mentioned, implement a boolean member to your Author interface and check that. The above would prevent you changing your class structures however.
This means that your novelist is in fact still an author, it just has it's own type. Your method signatures remain the same, your class structures remain the same you just have a type for a "different type of author", which should in theory be fine. Call as below to test.
GetBooks(new Novelist());
How about using a predicate for filtering?
class Search
{
public Books[] GetBooks(IAuthor author, Func<IAuthor, bool> filter){
// ...
}
}
search.GetBooks(author, a => a.IsNovelist)
In order to extend classes C# .NET introduced extension methods in .NET 3.5 whose main purpose is precisely to extend a class without modifying the existing code:
public static class SearchExtensions
{
public static Books[] GetBooksAsNovelist(this Search search, IAuthor author)
{
// Perform novelist search
}
}
Then you can invoke your Search class normally with:
Search.GetBooksAsNovelist(author);
You can use the Extension feature of C# language.
Please see http://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx
Extensions enable to add functionality to class by keeping the class intact.
In your case you can write as:
public static class SearchExtensions
{
public static Books[] GetBooks(this Search search, IAuthor author)
{
//new logic
}
}
You can access this new method by Search object and Search class also remains intact.
Please let me know if you find this helpful.
You could make your class partial to be able to add functionalyti without extensions, or inheritance, or inversion of control:
// file: Search.cs
partial class Search
{
public Books[] GetBooks(IAuthor author) { ... }
}
// file: Search.Advanced.cs
partial class Search
{
public Books[] GetBooksAsNovelist(IAuthor author) { ... }
}
Results:
http://i.snag.gy/VowNv.jpg
Keep the search class methods as virtual thus anyone can override them creating a new behavior?
I am not sure how to implement what I have in mind using C# .Net 3.5. I have a static class called Common which contains common methods. One of the method is PrepareReportParameters. This method accepts a string ReportParams and parse it to get the parameter values. I load this ReportParams string into a Dictionary . And then verify whether the required elements exist. I check that like:
if (ReportParamList.ContainsKey("PAccount"))
{
ReportParamList.TryGetValue("PAccount", out PrimaryAccount);
}
where PrimaryAccount is a static variable in my Common class. And I can access this elsewhere as Common.PrimaryAccount.
Though, this approcah of accessing the report parameters will work but I want PrimaryAccount to be accessed as Common.ReportParameters.PrimaryAccount.
Here is the problem, I don't know what type ReportParameters should be and how can I have all the report parameters added to this type? How should I define ReportParameters? Does it sound feasible or it doesn't make any sense. Please H E L P!
It sounds like you're basically used to using global variables to pass around state. That's generally a really bad idea.
Why doesn't your method just return the primary account value? That can then be passed to other things which need it.
If you find yourself with a lot of static members - and in particular if other classes are fetching mutable static variables - consider whether there's a more OO design you could apply. It'll be easier to understand, easier to test, and easier to maintain.
EDIT: Okay, so currently you have:
public static class Common
{
public static int PrimaryAccount;
// other static fields
public static void PrepareReportParameters(string reportParameters)
{
// Code to set the fields
}
}
Instead of that, use a normal class:
public class ReportParameters
{
public int PrimaryAccount { get; private set; }
// Other properties
private ReportParameters(int primaryAccount, ....)
{
this.PrimaryAccount = primaryAccount;
}
// Could use a constructor instead, but I prefer methods when they're going to
// do work
public static ReportParameters Parse(string report)
{
// Parse the parameter, save values into local variables, then
return new ReportParameters(primaryAccount, ...);
}
}
Then call this from the rest of your code, and pass the ReportParameters reference to anything that needs it.
You could create a class called ReportParameters with the relevant strongly-typed properties, and give Common a static instance of it?
I'm not sure this is the best design. Theres a certain amount of 'code smell' to having Common.PrimaryAccount only to be allowed to be accessed after PrepareReportParameters is called. Maybe you'd consider an instance class, passing in the parameters in the constructor?