Should I be using generics to simplify my configuration provider class? - c#

I am attempting to write a configuration manager that can supply configuration settings from different providers (e.g. settings files, environment variables, databases etc).
I have envisioned that the settings will be either strings, ints or doubles and will be identified by a name
Settings are provided via classes implementing this:
public interface IConfigurationManagerProvider
{
T GetSetting<T>(string name);
IEnumerable<ConfigurationSetting> GetKnownSettings();
}
As a start I am trying to write a provider to return environment variables
public class EnvironmentVariableProvider : IConfigurationManagerProvider
{
public T GetSetting<T>(string name)
{
string value = Environment.GetEnvironmentVariable(name);
return value as T;
}
public IEnumerable<ConfigurationSetting> GetKnownSettings()
{
return new List<ConfigurationSetting>
{
new ConfigurationSetting("MY_TRACING", typeof (String)),
};
}
}
however this won't compile as it can't cast to T.
If I put a class constraint in then this limits me to strings
public T GetSetting<T>(string name) where T : class
{
string value = Environment.GetEnvironmentVariable(name);
return value as T;
}
Really this provider can only supply strings (other providers will be different) however I want the code to access the configuration settings to be as clean as possible using something like:
public interface IConfigurationManagerConsumer
{
T GetConfiguration<T>(string name, T systemDefault);
}
and used like this:
string tracing = ConfigurationManager.GetConfiguration("MY_TRACING", "Unknown");
or this:
int maxUserCount = = ConfigurationManager.GetConfiguration("Max User Count", 10);
or this:
double pi = ConfigurationManager.GetConfiguration("PI", 3.14159);
Am I going in the right direction?

use Convert.ChangeType
return (T)Convert.ChangeType(value, typeof(T));

I have a vaguely similar variable provider interface, in which I didn't use generics. I started out with generics, and found that it didn't make the code any more readable or performant, particularly since the types were few and known from the start. After all, you're not getting anything dynamic, it is inferring the type from the default value you give. I also wanted my variable provider to be usable without providing a default value, and didn't want to use a different syntax for that.
So mine consists of two levels. One is public interface provider that I use in code, which can be used like in these examples:
IVariableProvider var;
// providing default value
double pi = var.Double["pi", 3.14159];
// no default value, also bool is just an int, converted by the IVariableProvider.
bool answer = var.Bool["answer"];
int number = var.Int["number"];
if(var.Str.ContainsKey("text"))
{
string text = var.Str["text"];
...
}
I could add public interfaces for var.Float, var.Long, etc if desired.
Underneath, the IVariableProvider can be given different "sources" to get variables from. The sources only expose string and integer. It can use other IVariableProviders as sources as well. When I call var.Double["pi"], it checks if any of the sources can provide a string variable for the key "pi" and then double.Parse() and return it.
Ultimately, you can do it either way. If you use generics like that and then want to use it without default values, you'll have to use different syntax in order to specify the type.

Related

Is it possible to set custom (de)serializers for open generic types in ServiceStack.Text?

I have a type like this:
class Foo<T>
{
public string Text { get; set; }
public T Nested { get; set; }
public static string ToJson(Foo<T> foo) { [...] }
}
ToJson serializes a Foo<Bar> instance to JSON in a way that is impossible to achieve by tweaking JsConfig. Also, ToJson relies on ServiceStack.Text to serialize Nested, which can be an instance of Foo<Baz>.
Unfortunately, the way JsConfig is implemented implies that there will be a JsConfig<T> set of static variables for Foo<Bar> and other for Foo<Baz>. Also, AFAIK, ServiceStack.Text offers no way to configure JSON serialization for open generic types (i.e.: something like JsConfig.Add(typeof(Foo<>), config)). I tried to solve this issue by creating this static constructor for Foo<T>:
static Foo() {
JsConfig<Foo<T>>.RawSerializeFn = ToJson;
}
This doesn't work all the time. It depends on the order the static constructors are invoked by the runtime. Apparently, ServiceStack.Text caches serializers functions and sometimes is doing it before the static constructor is called depending on the order operations are invoked in the API, so:
var outer = new Foo<Baz> { Text = "text" };
outer.ToJson(); // OK, because Nested is null
var inner = new Foo<Bar>();
inner.ToJson(); // OK, because JsConfig<Foo<Bar>>.RawSerializeFn is Foo<T>.ToJson
outer.Nested = inner;
outer.ToJson(); // NOT OK, because SS.Text uses the default serializer for Foo<T>, not Foo<T>.ToJson
I can't set all the serializers in JsConfig<Foo<T>> beforehand because T can be virtually any type, even other generic types.
Is it possible to define custom serialization routines for open generic types (that can be nested) in ServiceStack.Text?
I solved for this in my own way with a wrapper and a custom deserializer. I created a base type for all of my abstract types. That base type tells the system which type it is:
public class SetSettingItemBase
{
public string Key { get; set; }
public string ValueType { get; set; }
}
So the base is essentially the metadata -- the setting key + the value type. The object DTO, then, simply extends it by adding the actual value:
public class SetSettingItem : SetSettingItemBase
{
public object Value { get; set; }
}
Note that it's just an object. This is the DTO, not my actual object. I can cast it later, or convert it to a real/generic type after serialization.
My custom serialization then is:
JsConfig<SetSettingItem>.RawDeserializeFn = str =>
{
var baseSettings = str.FromJson<SetSettingItemBase>();
var ret = baseSettings.MapTo<SetSettingItem>();
if(true) // actual condition removed here... unimportant to the example
{
var dataType = Constants.KnownSettingsTypes[baseSettings.ValueType];
var method = typeof(JsonExtensions).GetMethod("JsonTo").MakeGenericMethod(dataType);
var key = "Value";
var parsed = JsonObject.Parse(str);
if(parsed.Object(key) == null)
key = "value";
ret.Value = method.Invoke(null, new object[] { parsed, key });
}
return ret;
};
This method first deserializes to the simple base. So the Value passed in from the DTO is ignored when deserializing baseSettings. I then call MapTo to prepare the actual SetSettingItem DTO. MapTo is just a wrapper around AutoMapper. You could just as easily use SS's built in mapper here.
For security, I have a set list of types that I allow as settings. Example:
KnownSettingsTypes.Add("string", typeof(string));
KnownSettingsTypes.Add("int", typeof(int));
KnownSettingsTypes.Add("nullableint", typeof(int?));
KnownSettingsTypes.Add("nullablepercentage", typeof(double?));
KnownSettingsTypes.Add("feegrid", typeof(FeeGrid));
After that, I use reflection to get the JsonTo method, passing in the generic type parameter dynamically from the KnownSettingsTypes dictionary.
And then finishing it all up, I parse the object using the generic JsonObject.Parse method and then looking for the Value or value (depending on case sensitivity) and explicitly convert that JsonObject using the dynamic method I created earlier.
The end result is I can pass in settings of all different types here as a part of my DTOs.
This served my purposes for the time being, but looking at the example I could see it improving in two ways:
After parsing, I could convert my SetSettingItem to a SettingItem<T> so I could use it as a strongly-typed object in my code. Remember, this example is just for the DTOs to get it across the wire.
Instead of requiring the person to pass in the type for me to check against, I could check against the setting Key to know which type it is supposed to be and parse accordingly. In my example, even if I check against the master list of settings and their types, I'd still probably require them to pass in the type just as a precaution and throw an exception if they didn't match.

C#: Create instance of a type based on an integral Enum value

I have an interface for implementing an "output formatter" that looks a bit like this:
public interface IFormatOutput {}
public class HtmlOutputFormatter : IFormatOutput {}
public class TextOutputFormatter : IFormatOutput {}
// etc, etc...
public enum OutputFormat {
Html,
Text,
HappyMeal,
Excel
}
public class SomeFormattableEntity {
int Id { get; set; }
OutputFormat OutputType { get; set; }
}
So SomeFormattableEntity is persisted in a database via Dapper and its OutputType property is stored as the underlying integer value (ie, in an INT column). As you can guess, I want to provide an instance of a IFormatOutput to handle a SomeFormattableEntity based on its OutputType property.
Is there some clean best-practice way to handle this type of relationship? My ideas so far include a factory with innards potentially consisting of:
grandpa's horrible ugly switch statement
an array mapping the enum value to a Type
reflection-based magic mapping enum member name as string to class type elsewhere
some mapping mechanism involving attributes
I realize it is not desirable to require an instance of a thing whose type is based on a value, but it seems hard to avoid this when SQL is involved. Basically the problem is that multiple "things" that all have varying .NET types are stored in a single table. I keep running into this idiom and am unable to find an elegant solution to it.
I'd probably go for a custom attribute with a FormatsOutputFor property. Then decorate all of your implementations of IFormatOutput with the attribute. e.g.
[YourAttribute(OutputFormat.Html)]
public class HtmlOutputFormatter : IFormatOutput {}
Then in your factory:
// get all your formatters
var formatters = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => Attribute.IsDefined(p, typeof(YourAttribute)));
// Now go through each formatter and use the attribute to figure out which
// output format it's for. Add these to some static IDictionary<OutputFormat, Type>
You probably want to build some internal cache that maps an OutputFormat value to a Type. Then your factory can double check that you have only got one type mapped to each output format and if you try to get a formatter for an enum value that doesn't have a corresponding class then you wont get some obscure TypeLoadException from activator.
Hopefully that makes sense...
How about:
OutputFormat format = OutputFormat.Excel;
object obj = Activator.CreateInstance("myAssemblyName", format.ToString());
Assuming the elements of your enum has the exact name of your types?

treat Enum as generic?

I'm trying to find a way to treat enums generically but I can't find a way to make it work. Say I have several enums declared something like this:
public enum ABC {
One,
Two,
Three
}
public enum DEF {
Four,
Five,
Six
}
and I want to write a method that takes an Enum as a parameter and simply returns name of the enum like this:
public string GetEnumName(Enum anEnum) {
return anEnum.GetType().Name;
}
but if I call it like GetEnumName(DEF); I get the 'is a type being used as a variable' error. Any ideas? thanks
EDIT Sorry judging by the replies I may not have been clear enough. I merely chose GetEnumName as a very simplistic example to illustrate the problem, not how to get the name from a type. Basically I want a method that I can pass ANY enum to and have it act on that enum directly, thanks
Use:
public static string GetTypeName<T>()
{
return typeof(T).Name;
}
Usage:
var result = GetTypeName<DEF>();
Perhaps this will do the trick?
public static class EnumExtensions
{
public static string GetEnumName<T>(this T value) where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
throw new InvalidOperationException(string.Format("{0} is not an enum", type));
return type.GetEnumName(value);
}
}
What you want to write is something like this:
public string GetEnumName<T>() where T : Enum
{
return typeof(T).Name;
}
That is, a generic method with a type parameter constraint.
Unfortunately, there is no way to define such a constraint for enums in C# (nor it is possible to define one for delegates). People usually go for the solution mentioned by #ananthonline.
In fact such constraint is not supported by the C# language but it is supported at the CLR level. Using a tool like Mono.Cecil for example can help you to modify your assembly and apply the constraint on the method after you get it compiled.
Have a look to this article: Constraining generic constraints
You'll find a tool which eases the process of applying non-C#-supported generic type parameter constraints: Cecil constraint patcher
And don't forget there are a lot of useful static methods on the Enum class if you want to work with the names and values of your enum members.
Your problem is that you are passing in the type instead of the System.Type. Change your method to this:
public string GetEnumName(Type enumType) {
return enumType.Name;
}
Just pass the type:
public string GetEnumName(Type enumType)
{
return enumType.Name;
}
And
GetEnumName(typeof(ABC));
At this point if your method does nothing else you could probably just use typeof(ABC).Name instead.
You can't. Generic constraints are not allowed on enum types (including System.Enum). Use Enum.GetName instead.

Constrain type to specific types

Is it possible to constrain a generic method on specific types?
I want to write something like this:
public T GetValue<T>(string _attributeValue) where T : float, string
{
return default(T); // do some other stuff in reality
}
I'm mostly just trying to avoid having a giant switch statement inside the method or having to throw an exception if an invalid type is specified.
Edit: Ack. I knew string is not a value type. I started out with two numeric types earlier. Sorry.
You can't use generic constraints to express the limitations you are interested in. Generics are not meant to express variation based on disjoint types - they're meant to express variation that is unified over a hierarchy of types (or those implementing certain interfaces).
You have a few alternative choices, however. Which you choose depends on the exact nature of what you're trying to do.
Use differently named methods to express each operation. I tend to use this approach when each method is truly doing something different. You could argue that returning a different type of value from a method is essentially a different operation, and deserves its own unique name.
float GetFloat(string attrName) { }
string GetString(string attrName) { }
Provide a "default value" to allow the type to be inferred. In many designs where you ask for a value by name it useful to supply a default value. This can allow you to employ overloading to differentiate between which method to invoke (based on the type of the default value). Unfortunately, this approach is quite fragile - and breaks easily when passing literal values to overloads that accept numeric primitives (int vs. uint vs. long).
float GetValue(string attrName, float defaultValue) { ... }
string GetValue(string attrName, string defaultValue) { ... }
Use a generic method, but throw a runtime exception if the type isn't one of those you support. Personally I find this kind of ugly and in violation of the spirit of generics - generics should unify functionality over a hierarchy or a set of types implementing some interface. However, in some cases it makes sense to do so (if let's so one specific type cannot be supported, let's say). Another problem with this approach is that the signature of the generic method cannot be inferred from any parameters, so you would have to specify the type desired when calling it ... at which point it's not much better (from a syntax point of view) than having different method names.
T GetValue<T>( string attrName )
{
if( typeof(T) != typeof(string) ||
typeof(T) != typeof(float) )
throw new NotSupportedException();
return default(T);
}
// call it by specifying the type expected...
float f = GetValue<float>(attrName);
string s = GetValue<string>(attrName);
Use an out parameter instead of a return value. This approach works well, but it loses the concise syntax of being able to call a method and act on a return value, since you first have to declare a variable to populate.
void GetValue( string attrName, out float value )
void GetValue( string attrName, out string value )
// example of usage:
float f;
GetValue( attrName, out f );
string s;
GetValue( attrName, out s );
This is not possible to do with compile time support. You can do this check in the static constructor and throw an exception (in the case the T is defined on the type) or (in your case) in the method body itself, but in that case it would be a runtime validation.
No, you can not specify a range of types. If you want all primatives you can do (and i know string is not included)
where T: struct
No, it's not possible.
And string is a reference type, not a value type.
The closest you can get is constraining on all value types (minus Nullable types):
public T GetValue<T>(string _attributeValue) where T : struct
Depending on what you're actually doing inside the method, there may be various ways to achieve your goal (other than switch/case). Consider changing your example to be a little more meaningful...
One other option might also be to make your method private and provide public wrappers that are specific:
private T GetValue<T>(string _attributeValue) where T : struct
{
return default(T);
}
public float GetFloatValue(string _attributeValue)
{
return GetValue<float>(_attributeValue);
}
public int GetIntValue(string _attributeValue)
{
return GetValue<int>(_attributeValue);
}
That would allow you to constrain the public members of your class to the desired types but still use generic code internally so you don't have to repeat yourself.

Less defined generics in c#?

Is there a way to use a collection of a generic class, without supplying the underlying type ?
Let's explain :
Here is what I'd like to have :
class TimeSerie<TValue> {
enter code here
}
List<TimeSerie<?>> blah;
Here is what I have to do so far :
class TimeSerie {}
class TypedTimeSerie<TValue> : TimeSerie {}
List<TimeSerie> blah;
So, any way to use the nice first solution ? (although I guess it would raise problems when trying to cast, for a loop for example ...)
You can make your using code generic too... but at some point you do have to specify the type argument. You're not going to be able to create an instance of the generic type without the type argument being known. You can provide that information at execution time using reflection if you must, but it has to be there somehow.
I dont see based on your question why you cannot derive your custom collection from ICollection<T> or List<T> (or maybe derive from ICollection and delegate the calls to a field of type List<T> you store internally?
(It's entirely possible I'm just not getting it, but can you give a small bit more sample code?)
Why not ?
List<TimeSerie<Object>> blah;
Then after you specify your object. Also define your base class accordingly.
Note that some 'mumbling' is possible in relation to anonymous types with c# thanks to two things:
Type inference
unification of identical anonymous types
If you are happy to rely on these two things remaining fixed (there are no guarantees on this, especially in relation to 2) then the following may be useful.
public static class Mumble
{
public static HashSet<T> HashSet<T>(T prototype)
{
return new HashSet<T>();
}
public static List<T> List<T>(T prototype)
{
return new List<T>();
}
}
You can use it like so:
var set = MumbleSet(new { Foo="", Bar="", Baz=0 });
var list = MumbleList(new { Foo="", Bar="", Baz=0 });
set.Add(new { Foo="x", Bar="y", Baz=1 });
set.Add(new { Foo="a", Bar="b", Baz=1 });
list.Add(new { Foo="a", Bar="b", Baz=1 });
var intersection = list.Intersect(set);
var concat = list.Concat(set);
This works well in cases where you have anonymous types you wish to populate into some other collection for use elsewhere within a method. A common use would be reading from a database query into a set for latter checking for existence within a loop where expressing this as a series of linq queries was either too cumbersome or too expensive.
For your motivating example you would have to add the following:
class TimeSerie<TValue>
{
// or some other constructor equivalent
public TimeSerie(TValue value) { /* assign the value */ }
}
static class TimeSerieMumble
{
public static TimeSerie<TValue> New<TValue>(TValue value)
{
return new TimeSerie<TValue>(value);
}
}
Then you could use the code like so:
var tsList = Mumble.List(TimeSerieMumble.New(new { Name="", Value=0 }));
foreach (var x in from c select new { c.Name, c.Value })
{
tsList.Add(TimeSerieMumble.New(new { x.Name, x.Value }));
}
Mumbling which 'leaks' into the public api is not feasible in c# 3.5 unless the type is to be mumbled through a series of type inferred generic methods in the same way as the above example. I have never seen a case where such a thing was useful given the resulting contortions required to the calling code. I would not think it would improve readability either. As a rule of thumb using more than the two levels of mumbling in the Name/Value example is likely to lead to serious complications down the line.
As others have said, there's no easy way to do this in C#.
However, if it's really important, it is possible to faithfully encode this pattern using a few extra types, although it's a bit ugly:
interface ITimeSeriesUser<X> {
X Use<T>(TimeSeries<T> series);
}
interface ITimeSeriesUser {
void Use<T>(TimeSeries<T> series);
}
interface ITimeSeries {
X Apply<X>(ITimeSeriesUser<X> user);
void Apply(ITimeSeriesUser user);
}
class TimeSeries<T> : ITimeSeries {
X Apply<X>(ITimeSeriesUser<X> user) { return user.Use(this); }
void Apply(ITimeSeriesUser user) { return user.Use(this); }
/* Your existing code goes here */
}
Now you can create a List<ITimeSeries> instance which holds TimeSeries<T>
values regardless of their type arguments, and you can use ITimeSeriesUser
implementations to manipulate them. Obviously this requires quite a bit of boilerplate,
but if you need a faithful way to express the concept of a TimeSeries<?> then this may be your best bet.

Categories

Resources