Factory driven by enum attributes - c#

I have a situation where a factory pattern seems appropriate like this:
enum Food {
Cake,
Cookies,
Milk,
CannedBeans
}
public static class FoodMetaDataFactory{
public static IFood GetMetaData(Food foodType){ //takes a food enum value as a parameter
switch(foodType){
case Food.Milk:
return new MilkMetaData();
case Food.CannedBeans:
return new CannedBeansMetaData();
case Food.Cookies:
return new CookiesMetaData();
case Food.Cake:
return new CakeMetaData();
}
}
}
However, I'd rather have more declarative pattern like this:
enum Food {
[FoodMetaDataAttribute(typeof(CakeMetaData))]
Cake,
[FoodMetaDataAttribute(typeof(CookiesMetaData))]
Cookies,
[FoodMetaDataAttribute(typeof(MilkMetaData))]
Milk,
[FoodMetaDataAttribute(typeof(CannedBeansMetaData))]
CannedBeans
}
public static class FoodMetaDataFactory{
public static IFood GetMetaData(Food foodType){ //takes a food enum value as a parameter
//reflectively retrieve FoodMetaDataAttribute
Type enumType = typeof(Food);
var memInfo = enumType.GetMember(foodType.ToString());
//assume one item returned
var foodMetaDataAttributes = memInfo[0].GetCustomAttributes(typeof(FoodMetaDataAttribute),
false);
// now access the property telling us the concrete type of the metadata class(this is the type passed in the attribute's declaration
Type targetType = ((FoodMetaDataAttribute)foodMetaDataAttributes[0]).MetaDataProviderType;
//not done yet, now we need to reflectively instantiate targetType, something like this
ConstructorInfo ctor = targetType.GetConstructor(new[] { });
//invoke the constructor, returning concrete instance such as CakeMetaData
return ctor.Invoke(new object[] {}) as IFood;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class FoodMetaDataAttribute : Attribute
{
public FoodMetaDataAttribute(Type metaDataProviderType){
MetaDataProviderType = metaDataProviderType;
}
public Type MetaDataProviderType { get; set; }
}
I like this because it is clear to anyone adding new values to the enum that they need a meta data class and declare it in the attribute. This IMO is better than having to remember to modify the switch case in a factory.
It seemed simple at first until I started to think about the implementation of GetMetaData that has to reflectively retrieve the attribute, the typeof parameter, and then reflectively instantiate the MetaData class. I'm not experienced in creating attribute classes, so the primary driver of this question is a hope that maybe there's a simpler way to accomplish this with attributes. If attribute classes didn't have so many restrictions, such as on using generic types, I'd have this done in a way I liked with some compile time safety.
This proposed solution has no compile time safety. You can pass in types to the attribute that don't implement IFood, which is the minimum requirement for MetaData classes such as MilkMetaData. If attributes allowed generic type parameters I'd use that instead of typeof and could apply a where T:IFood
Is there a better way to utilize attributes to accomplish this mapping from enum value to concrete class?

What I usually do in these cases is create a dictionary of factories, e.g.:
private IDictionary<MyEnum, Func<IMyInterface>> Factories = new Dictionary<MyEnum, Func<IMyInterface>> {
{ MyEnum.MyValue, () => new MyType() },
// etc.
}
Simple and easy to maintain, extend or validate. You can create instance by doing:
IMyInterface instance;
if(!Factories.TryGetValue(enumValue, out instance))
throw new Exception(string.Format("No factory for enum value {0}", enumValue));
return instance;
Note that separating the enum from the actual instance should be a good thing (split implementation from data). Otherwise, I suggest you simply pass on the actual type to a generic method.

I'm not 100% sure that there is not a completely different approach that would be better, but there is just couple things you can improve in your current code:
You can use Activator.CreateInstance(type) instead of getting the constructor:
return Activator.CreateInstance(targetType) as IFood;
You can also consider some kind of cache, to avoid doing all the reflection-related work on every single call. You can either store a single instance of concrete IFood implementation for each enum value, using simple dictionary:
public static class FoodMetaDataFactory
{
private static Dictionary<Food, IFood> _cache = new Dictionary<Food, IFood>();
public static IFood GetMetaData(Food foodType)
{ //takes a food enum value as a parameter
IFood value;
if (!_cache.TryGetValue(foodType, out value))
{
lock (_cache)
{
if (!_cache.TryGetValue(foodType, out value))
{
var enumType = typeof(Food);
var memberInfo = enumType.GetMember(foodType.ToString());
var foodMetaDataAttributes = memberInfo[0].GetCustomAttributes(typeof(FoodMetaDataAttribute), false);
var targetType = ((FoodMetaDataAttribute)foodMetaDataAttributes[0]).MetaDataProviderType;
value = Activator.CreateInstance(targetType) as IFood;
_cache.Add(foodType, value);
}
}
}
return value;
}
}
or if you need each call to return fresh instance instead of shared one, you can use Expression Trees, to generate a Func<IFood> lambda expression when GetMetaData is called for the first time for given enum value, and call it later instead of reflection-processing.
About compile-time safety: I'm afraid you'd have to write your own custom check about that, e.g. as FxCop custom rule, or maybe something using Roslyn, if you're using newest (beta) version of Visual Studio.

New here. To start from the end, If you want to use these Enum values for display, the best way to do it is to decorate them with an attribute that is a display string (or CSV), but if the values need to be complex, you should be using a Factory Method that creates new Food types. A base class can contain common values while each successive Child class has specifics that can then always be fed to the UI mechanism.
This only works if either each type creates it's own View or the views are common between types. This is similar to dependency injection in the second idea.
But if you want to add additional enums that represent code paths, you have to ALWAYS update your Controller\ViewModel unless there is some generic model that is always used for display.
I don't know your code base, so I don't know what type of refactoring would be required for a Factory or Adapter pattern.

Related

List of generic delegates (e.g. System.Converter<TInput, TOutput>)

Is it possible to create a list of generic delegates, like System.Converter<TInput, TOutput>?
In java that could be List<Converter<?,?>>, but with Java's type erasure that's not very useful. Seems like in C# it should be possible to query the generic types after retrieval from the list and use the obtained instance to perform the desired conversion.
Elaborating on the question:
I have user supplied data in user provided formats which I know nothing about at compile time. Algorithms in my program know how to work with its own specific data types, of course. The goal is to have an equiavalent of Java's List<Converter<?,?>> where Converters can be installed (by me, or users) and queried automatically by the program to see if user's data can be converted to the required format for an algorithm.
This is very rudimentary and is only intended to show the basic concept.
It has:
A dictionary keyed on a 2-tuple of input and output types to hold converter instances.
A Register method to use for registering converters. Registering the same pair of types overwrites a previously registered converter. You can easily change it to be a no-op or an exception.
A Convert method to call a registered converter. It would be very trivial to create a TryConvert method if you needed it.
public static class ConverterContainer
{
private static readonly Dictionary<(Type, Type), Delegate> _converters = new Dictionary<(Type, Type), Delegate>();
public static void Register<TInput, TOutput>(Func<TInput, TOutput> converter)
{
if (converter is null)
throw new ArgumentNullException(nameof(converter));
_converters[(typeof(TInput), typeof(TOutput))] = converter;
}
public static TOutput Convert<TInput, TOutput>(TInput input)
{
if (_converters.TryGetValue((typeof(TInput), typeof(TOutput)), out var del))
{
Func<TInput, TOutput> converter = (Func<TInput, TOutput>)del;
return converter(input);
}
throw new InvalidOperationException("Converter not registered.");
}
}
What it does not have:
thread safety. This is left as an exercise to a serious implementor.
possibly other things I didn't take the time to consider.
How to use it:
At startup of your application, register converters, like registering services for dependency injection.
ConverterContainer.Register<long, int>(l => (int)l);
// ... etc.
And wherever you want to perform conversion between a registered pair of input/output types:
int x = ConverterContainer.Convert<long, int>(1000L)
Unfortunately, you do have to specify both type arguments here.
Addition from the OP:
To not have to specify the input parameter type (which is kind of the point of having a dynamic list of available conversions) use the following additional method in the sample ConverterContainer above (as #madreflection has suggested in the comments himself) :
public static TOutput Convert<TOutput>(object toConvert) {
if (toConvert is null)
throw new ArgumentNullException(nameof(toConvert));
if (Converters.TryGetValue((toConvert.GetType(), typeof(TOutput)), out Delegate conv)) {
object o = conv.DynamicInvoke(toConvert);
return (TOutput) o;
}
throw new InvalidOperationException($"Converter not registered for types: {toConvert.GetType().Name} -> {typeof(TOutput).Name}");
}
You can now throw in any random object instance and see if the conversion to your desired type is possible.
In C# all the converters in the list will share the same type parameters (TInput, TOutput). Unless you have a non generic interface IConverter, you will not be able to store multiple converter in anything else than a list of object.
You can anyway try to cast the elements into what you need like it is done here (with a dictionary). Hirerate trough an heterogeneous and type-safe dictionary
No, you can't.
You have to make a Generic Method or Generic class like this:
void MyMethod<TInput, TOuput>()
{
List<Converter<TInput, TOuput>> myList = new List<Converter<TInput, TOuput>>();
}

ReSharper warns: "Static field in generic type"

public class EnumRouteConstraint<T> : IRouteConstraint
where T : struct
{
private static readonly Lazy<HashSet<string>> _enumNames; // <--
static EnumRouteConstraint()
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException(
Resources.Error.EnumRouteConstraint.FormatWith(typeof(T).FullName));
}
string[] names = Enum.GetNames(typeof(T));
_enumNames = new Lazy<HashSet<string>>(() => new HashSet<string>
(
names.Select(name => name), StringComparer.InvariantCultureIgnoreCase
));
}
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
bool match = _enumNames.Value.Contains(values[parameterName].ToString());
return match;
}
}
Is this wrong? I would assume that this actually has a static readonly field for each of the possible EnumRouteConstraint<T> that I happen to instance.
It's fine to have a static field in a generic type, so long as you know that you'll really get one field per combination of type arguments. My guess is that R# is just warning you in case you weren't aware of that.
Here's an example of that:
using System;
public class Generic<T>
{
// Of course we wouldn't normally have public fields, but...
public static int Foo;
}
public class Test
{
public static void Main()
{
Generic<string>.Foo = 20;
Generic<object>.Foo = 10;
Console.WriteLine(Generic<string>.Foo); // 20
}
}
As you can see, Generic<string>.Foo is a different field from Generic<object>.Foo - they hold separate values.
From the JetBrains wiki:
In the vast majority of cases, having a static field in a generic type
is a sign of an error. The reason for this is that a static field in a
generic type will not be shared among instances of different close
constructed types. This means that for a generic class C<T> which
has a static field X, the values of C<int>.X and C<string>.X
have completely different, independent values.
In the rare cases when you do need the 'specialized' static fields,
feel free to suppress the warning.
If you need to have a static field shared between instances with
different generic arguments, define a non-generic base class to
store your static members, then set your generic type to inherit from
this type.
This is not necessarily an error - it is warning you about a potential misunderstanding of C# generics.
The easiest way to remember what generics do is the following:
Generics are "blueprints" for creating classes, much like classes are "blueprints" for creating objects. (Well, this is a simplification though. You may use method generics as well.)
From this point of view MyClassRecipe<T> is not a class -- it is a recipe, a blueprint, of what your class would look like. Once you substitute T with something concrete, say int, string, etc., you get a class. It is perfectly legal to have a static member (field, property, method) declared in your newly created class (as in any other class) and no sign of any error here.
It would be somewhat suspicious, at first sight, if you declare static MyStaticProperty<T> Property { get; set; } within your class blueprint, but this is legal too. Your property would be parameterized, or templated, as well.
No wonder in VB statics are called shared. In this case however, you should be aware that such "shared" members are only shared among instances of the same exact class, and not among the distinct classes produced by substituting <T> with something else.
There are several good answers here already, that explain the warning and the reason for it. Several of these state something like having a static field in a generic type generally a mistake.
I thought I'd add an example of how this feature can be useful, i.e. a case where suppressing the R#-warning makes sense.
Imagine you have a set of entity-classes that you want to serialize, say to Xml. You can create a serializer for this using new XmlSerializerFactory().CreateSerializer(typeof(SomeClass)), but then you will have to create a separate serializer for each type. Using generics, you can replace that with the following, which you can place in a generic class that entities can derive from:
new XmlSerializerFactory().CreateSerializer(typeof(T))
Since your probably don't want to generate a new serializer each time you need to serialize an instance of a particular type, you might add this:
public class SerializableEntity<T>
{
// ReSharper disable once StaticMemberInGenericType
private static XmlSerializer _typeSpecificSerializer;
private static XmlSerializer TypeSpecificSerializer
{
get
{
// Only create an instance the first time. In practice,
// that will mean once for each variation of T that is used,
// as each will cause a new class to be created.
if ((_typeSpecificSerializer == null))
{
_typeSpecificSerializer =
new XmlSerializerFactory().CreateSerializer(typeof(T));
}
return _typeSpecificSerializer;
}
}
public virtual string Serialize()
{
// .... prepare for serializing...
// Access _typeSpecificSerializer via the property,
// and call the Serialize method, which depends on
// the specific type T of "this":
TypeSpecificSerializer.Serialize(xmlWriter, this);
}
}
If this class was NOT generic, then each instance of the class would use the same _typeSpecificSerializer.
Since it IS generic however, a set of instances with the same type for T will share a single instance of _typeSpecificSerializer (which will have been created for that specific type), while instances with a different type for T will use different instances of _typeSpecificSerializer.
An example
Provided the two classes that extend SerializableEntity<T>:
// Note that T is MyFirstEntity
public class MyFirstEntity : SerializableEntity<MyFirstEntity>
{
public string SomeValue { get; set; }
}
// Note that T is OtherEntity
public class OtherEntity : SerializableEntity<OtherEntity >
{
public int OtherValue { get; set; }
}
... let's use them:
var firstInst = new MyFirstEntity{ SomeValue = "Foo" };
var secondInst = new MyFirstEntity{ SomeValue = "Bar" };
var thirdInst = new OtherEntity { OtherValue = 123 };
var fourthInst = new OtherEntity { OtherValue = 456 };
var xmlData1 = firstInst.Serialize();
var xmlData2 = secondInst.Serialize();
var xmlData3 = thirdInst.Serialize();
var xmlData4 = fourthInst.Serialize();
In this case, under the hood, firstInst and secondInst will be instances of the same class (namely SerializableEntity<MyFirstEntity>), and as such, they will share an instance of _typeSpecificSerializer.
thirdInst and fourthInst are instances of a different class (SerializableEntity<OtherEntity>), and so will share an instance of _typeSpecificSerializer that is different from the other two.
This means you get different serializer-instances for each of your entity types, while still keeping them static within the context of each actual type (i.e., shared among instances that are of a specific type).

How to create instance of a class from class name without using reflection?

Is there any way to achieve something like this?
If "Employee" is passed as an argument to a method it should return an object of type Employee.
But without using reflection.
You could use Type.GetType(string) to get the meta data for the type. However, this requires an Assembly Qualified Name of the type unless the type resides in the currently executing assembly or is part of mscorlib.dll.
Then you can use Activator.CreateInstance(Type) to obtain an instance.
var type = Type.GetType(typeName);
var obj = Activator.CreateInstance(type);
At this point, the static type of obj is System.Object. You would need to continue using reflection to get at the properties and methods defined on your actual type, or you could treat the object as dynamic, assuming you don't know at compile time what class to cast the result to (and if you did know, you would skip this entire process).
Edit: With your added constraint of not wanting to use reflection, this changes your options. The code will not be quite as dynamic in regards to what you can support, you will generally need to have an idea ahead of time, but that might be a good thing, depending on what you are trying to accomplish. What you might have is simply a switch statement or a dictionary that has supported types, keying on the name as a string.
public object GetInstanceOf(string typeName)
{
switch (typeName)
{
case "Employee": return new Employee();
case "Manager" : return new Manager();
case "Owner" : return new Owner();
// etc
default:
throw new InvalidOperationException("typeName is not supported");
}
}
Notice with this approach, you know all of your supported types in advance. There are other ways to know the types in advance outside of code (ex: configuration, data), but those would generally get you back into the land of the first part of the answer. Also note that your return type is still limited. It must be a common base type or interface for the classes involved. In my code sample, it's the common base type for all classes and structs, System.Object. For you, this might be more of a factory, with a Worker base class or IWorker interface. Or maybe Employee is the base and your method is constructing specialized children of it. The latter two examples give you compile-time access to the base or interface defined methods and properties.
Yes than you can do with the help of "Reflection"
Try
Employee employee =(Employee)Activator.CreateInstance("Employee");
check #jon skeet answer : How do I create an instance from a string in C#?
Instantiating an Arbitrary Type Without Reflection
I was wrong. There are a lot of ways that you can instantiate a type without true reflection, it would seem. I'll try to compile a list of all that I can find.
Generics
Depending on what you are trying to do, you might be able to do a very cool technique called generics. You can't input an arbitrary name of a type at runtime, so this doesn't necessarily answer your question in full, but if you know the types that you want at compile time, this makes for a great tool. This involves no reflection of any sort, but is entirely compile time. Here's an example:
interface IParsable
{
bool TryParse(string text);
}
class MyInt : IParsable
{
public int Value { get; private set; }
public static MyInt Parse(string text)
{
Parser parser = new Parser();
return parser.Parse<MyInt>(text);
}
}
class MyFloat : IParsable
{
public float Value { get; private set; }
public static MyFloat Parse(string text)
{
Parser parser = new Parser();
return parser.Parse<MyFloat>(text);
}
}
class Parser
{
// The "new()" constraint means that T must have a
// parameterless constructor.
private T Parse<T>(string text)
where T : IParsable, new()
{
// Even though T isn't actually a type, we can use
// it as if it were, for the most part.
T obj = new T();
// Because we had the IParsable constraint, we can
// use the TryParse method.
if (!obj.TryParse(text))
{
throw new Exception("Text could not be parsed.");
}
return obj;
}
}
Dictionary of Lambdas
Credit to Anthony Pegram for his genius on this one (see comments below). Previously I had this using reflection, but he fixed it to work without any reflection whatsoever, thanks to lambda expressions.
static readonly IDictionary<string, Func<object>> Types = new Dictionary<string, Func<object>>()
{
{ "TypeA", () => new TypeA() },
{ "TypeB", () => new TypeB() },
{ "TypeC", () => new TypeC() },
};
// If you're okay with a bit of reflection behind-the-scenes, change "object"
// here to "dynamic", and you won't have to cast down the road.
object void GetInstance(string name)
{
if (Types.ContainsKey(name))
{
return Types[name]();
}
else
{
return null;
}
}
Pre-Instantiated Objects
Yet another option would be to return the same reference each time. This avoids "true" reflection altogether. This idea of reusing instances has some important implications, which could be either good or bad, depending on what you are doing. These implications are very interesting, and can be quite amazing if used properly.
You could, if you wanted, have each type implement a specific interface, and cast to that, instead of returning a raw object.
static readonly IDictionary<string, object> Instances = new Dictionary<string, object>()
{
{ "TypeA", new TypeA() },
{ "TypeB", new TypeB() },
{ "TypeC", new TypeC() },
};
object void GetInstance(string name)
{
if (!Instances.ContainsKey(name))
{
return null;
}
return Instances[name];
}
Instantiating an Arbitrary Type With Reflection
You've got a nice array of answers that will work great if your type has a parameterless constructor. But what if it doesn't?
const string TYPE = "System.String";
Type type = Type.GetType(TYPE);
if (type == null)
{
// Type doesn't exist--at least, not in mscorlib or current assembly,
// or we didn't specify the assembly.
throw new Exception("Could not find type " + TYPE + ".");
}
// Note the Type array. These are the types of the parameters that the
// constructor takes.
ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(char), typeof(int) });
if (ctor == null)
{
// Constructor doesn't exist that takes those parameters.
throw new Exception("Could not find proper constructor in " + TYPE + ".");
}
// Note the object array. These are the actual parameters passed to the
// constructor. They should obviously match the types specified above.
string result = (string)ctor.Invoke(new object[] { 'a', 5 });
You could use Activator.CreateInstance()
Employee employee =(Employee)Activator.CreateInstance("Namespace", "Employee");
Using reflection as #vulkanino says you will end with something like this:
Employee instance = (Employee)Activator.CreateInstance("MyNamespace.Employee, MyAssembly");
Hope this helps you.
Using reflection you can find types in assemblies, whether it be the executing assembly or other loaded ones (you may load them on demand, actually). Without specifying a complete example of how this might work in your scenario, you would then use something along the lines of Activator.CreateInstance to create instances of your found objects.

Expose Action<T> as Action<object>

I'm creating a framework that contains a wrapper around a library (specifically SharpBrake) that performs all interaction with SharpBrake via reflection so there's no hard dependency on the library to 3rd parties of my framework.
If 3rd parties of my framework wants to use SharpBrake, they can just stuff the SharpBrake.dll into the bin folder, but if they don't, they can just forget about it. If my framework had explicit references to SharpBrake types, users of my framework would get exceptions during runtime of SharpBrake.dll missing, which I don't want.
So, my wrapper first loads SharpBrake.dll from disk, finds the AirbrakeClient type, and stores a delegate pointing to the AirbrakeClient.Send(AirbrakeNotice) method in a private field. My problem, however, is that since the Send() method takes an AirbrakeNotice object and I can't reference the AirbrakeNotice object directly, I need to somehow convert the Send() method to an Action<object>.
I have a strong feeling this isn't possible, but I want to explore all options before settling on exposing Delegate and using DynamicInvoke(), which I assume is far from optimal, performance-wise. What I would love to do is the following:
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
Type noticeType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeNotice");
MethodInfo sendMethod = clientType.GetMethod("Send", new[] { noticeType });
object client = Activator.CreateInstance(clientType);
Type actionType = Expression.GetActionType(noticeType);
Delegate sendMethodDelegate = Delegate.CreateDelegate(actionType, client, sendMethod);
// This fails with an InvalidCastException:
Action<object> sendAction = (Action<object>)sendMethodDelegate;
However, this fails with the following exception:
System.InvalidCastException: Unable to cast object of type 'System.Action`1[SharpBrake.Serialization.AirbrakeNotice]' to type 'System.Action`1[System.Object]'.
Obviously, because sendMethodDelegate is an Action<AirbrakeNotice> and not an Action<object>. Since I can't mention AirbrakeNotice in my code, I'm forced to do this:
Action<object> sendAction = x => sendMethodDelegate.DynamicInvoke(x);
or just exposing the Delegate sendMethodDelegate directly. Is this possible? I know that there's chance of getting into situations where the object can be of a different type than AirbrakeNotice which would be bad, but seeing how much you can mess up with reflection anyway, I'm hoping there's a loophole somewhere.
If you're happy to use expression trees, it's reasonably simple:
ConstantExpression target = Expression.Constant(client, clientType);
ParameterExpression parameter = Expression.Parameter(typeof(object), "x");
Expression converted = Expression.Convert(parameter, noticeType);
Expression call = Expression.Call(target, sendMethod, converted);
Action<object> action = Expression.Lambda<Action<object>>(call, parameter)
.Compile();
I think that's what you want...
If you don't need below C# 4 support you can get much greater performance using the dynamic vs DynamicInvoke.
Action<dynamic> sendAction = x => sendMethodDelegate(x);
Actually I guess you wouldn't even need the above if you can use dynamic, because it would increase performance and simplify everything if you just did:
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
dynamic client = Activator.CreateInstance(clientType);
...
client.Send(anAirbrakeNotice);
But if you need to support .net 3.5 jon skeets answer with expression trees is definitely the way to go.
From my comment on the OP:
I'd avoid extended use of reflections if you are concerned about performance. If you can come up with an interface for the class(es) you are using, then I'd create one. Then write a wrapper that implements the interface by calling into the SharpBreak code, and stuff it in a separate DLL. Then dynamically load just your wrapper assembly and concrete wrapper type(s), and call into that interface. Then you don't have to do reflections at a method level.
I'm not sure all the classes you'd need, but here's a simple example of how you can hook into that library with loose coupling based on interfaces.
In your program's assembly:
public IExtensions
{
void SendToAirbrake(Exception exception);
}
public static AirbreakExtensions
{
private static IExtensions _impl;
static()
{
impl = new NullExtensions();
// Todo: Load if available here
}
public static void SendToAirbrake(this Exception exception)
{
_impl.SendToAirbrake(exception);
}
}
internal class NullExtensions : IExtensions // no-op fake
{
void SendToAirbrake(Exception exception)
{
}
}
In a load-if-available (via reflections) assembly
public ExtensionsAdapter : IExtensions
{
void SendToAirbrake(Exception exception)
{
SharpBrake.Extensions.SendToAirbrake(exception);
}
}
The advantage of this approach is that you only use reflections once (on load), and never touch it again. It is also simple to modify to use dependency injection, or mock objects (for testing).
Edit:
For other types it will take a bit more work.
You might need to use the Abstract Factory pattern to instantiate an AirbrakeNoticeBuilder, since you need to deal directly with the interface, and can't put constructors in interfaces.
public interface IAirbrakeNoticeBuilderFactory
{
IAirbrakeNoticeBuilder Create();
IAirbrakeNoticeBuilder Create(AirbrakeConfiguration configuration);
}
If you're dealing with custom Airbreak structures, you'll have even more work.
E.g. for the AirbrakeNoticeBuilder you will have to create duplicate POCO types for any related classes that you use.
public interface IAirbrakeNoticeBuilder
{
AirbrakeNotice Notice(Exception exception);
}
Since you're returning AirbrakeNotice, you might have to pull in nearly every POCO under the Serialization folder, depending on how much you use, and how much you pass back to the framework.
If you decide to copy the POCO code, including the whole object tree, you could look into using AutoMapper to convert to and from your POCO copies.
Alternately, if you don't use the values in the classes you're getting back, and just pass them back to the SharpBreak code, you could come up with some sort of opaque reference scheme that will use a dictionary of your opaque reference type to the actual POCO type. Then you don't have to copy the whole POCO object tree into your code, and you don't need to take as much runtime overhead to map the object trees back and forth:
public class AirbrakeNotice
{
// Note there is no implementation
}
internal class AirbreakNoticeMap
{
static AirbreakNoticeMap()
{
Map = new Dictionary<AirbreakNotice, SharpBreak.AirbreakNotice>();
}
public static Dictionary<AirbreakNotice, SharpBreak.AirbreakNotice> Map { get; }
}
public interface IAirbrakeClient
{
void Send(AirbrakeNotice notice);
// ...
}
internal class AirbrakeClientWrapper : IAirbrakeClient
{
private AirbrakeClient _airbrakeClient;
public void Send(AirbrakeNotice notice)
{
SharpBreak.AirbrakeNotice actualNotice = AirbreakNoticeMap.Map[notice];
_airbrakeClient.Send(actualNotice);
}
// ...
}
internal class AirbrakeNoticeBuilderWrapper : IAirbrakeNoticeBuilder
{
AirbrakeNoticeBuilder _airbrakeNoticeBuilder;
public AirbrakeNotice Notice(Exception exception)
{
SharpBreak.AirbrakeNotice actualNotice =
_airbrakeNoticeBuilder.Notice(exception);
AirbrakeNotice result = new AirbrakeNotice();
AirbreakNoticeMap.Map[result] = actualNotice;
return result;
}
// ...
}
Keep in mind that you only need to wrap the classes and parts of the public interface that you're going to use. The object will still behave the same internally, even if you don't wrap its entire public interface. This might mean you have to do less work, so think hard and try to wrap only what you need now, and what you know you're going to need in the future. Keep YAGNI in mind.
The programming style I have come to really like for problems like this is to write as much strongly-typed code as possible, and then hand off the logic from the dynamically-typed code to the strongly-typed code. So I would write your code like this:
//your code which gets types
Type clientType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeClient");
Type noticeType = exportedTypes.FirstOrDefault(type => type.Name == "AirbrakeNotice");
//construct my helper object
var makeDelegateHelperType=typeof(MakeDelegateHelper<,>).MakeGenericType(clientType, noticeType);
var makeDelegateHelper=(MakeDelegateHelper)Activator.CreateInstance(makeDelegateHelperType);
//now I am in strongly-typed world again
var sendAction=makeDelegateHelper.MakeSendAction();
And this is the definition of the helper object, which is able to get away with fewer reflectiony calls.
public abstract class MakeDelegateHelper {
public abstract Action<object> MakeSendAction();
}
public class MakeDelegateHelper<TClient,TNotice> : MakeDelegateHelper where TClient : new() {
public override Action<object> MakeSendAction() {
var sendMethod = typeof(TClient).GetMethod("Send", new[] { typeof(TNotice) });
var client=new TClient();
var action=(Action<TNotice>)Delegate.CreateDelegate(typeof(Action<TNotice>), client, sendMethod);
return o => action((TNotice)o);
}
}

"Store" a type parameter for later use in C#?

I'm creating a Settings object in my app, used for storing user-defined settings and whatnot. I plan on using various datatypes for my setting fields (ints, strings, enums, anything Serializable, really).
I'd also like, if possible, a type-safe way to set any of the settings. My proposed method would be doing something like this:
Tuple<string, Type> SettingName = new Tuple<string, Type>("NumberOfFoos",
typeof(**TYPE**));
public void Set(Tuple<string, Type> key, **TYPE** value) { /* Stuff */ }
The Tuple would effectively be the "setting" that the user would push a value to, and would consist of the key for that setting as well as the type of that setting. What I'm wondering is if there's any way to have the compiler enforce that, in the Set() method, the type of value is of the same type as the type object saved in the tuple passed to Set()? Is the way I proposed even possible? Thanks!
EDIT: I thought of some more things I should clarify.
1) This is intended to be a static class, so I won't be able to serialize the whole class, only members in it. Therefore, I'd really like to not have to deal with a serialization for each field. I was planning on storing all the setting values in a Dictionary<string, **TYPE**> and serializing that.
2) The Tuple definitions are meant to be constant and static. I'm really treating them as more of a typedef-type thing (I really should make my own SettingKey struct), which the user passes to Set to indicate what field they are changing. The Type parameter is meant to enforce the the value parameter is of the specified type.
Something like
public void Set<T>(Tuple<string,T> key, T value) { /* stuff */ }
might do it
It's better to get rid of the tuple, and use a generic method:
public void Set<T>(string key, T value);
That way, you can specify the type at compile-time
Set<string>("MyStringKey", "foo");
Set<int>("MyIntKey", 1);
or the compiler can infer it for you:
Set("MyStringKey", "foo");
Set("MyIntKey", 1);
and in Set, you can use typeof(T) to get the Type object you would have passed in.
Why not simply add strongly typed properties to your settings object? e.g. public int NumberOfFoos {get {} set {...}} and in the getter and setter call your common serialization and deserialization code.
If you do this your settings object isn't exposing how it works internally and you have full intellisense support on it.
Well, if you did something like Set<T>(Tuple<string, T>, T value), you'd get what you're after for setting. And I think the compiler could infer the T in Set<T>() at usage, so you would have to write it.
But your Get<T>(), you'd have to specify the type you expected to get back.
public class Foo
{
Tuple<string, Type> SettingName = new Tuple<string, Type>("NumberOfFoos",
typeof(**TYPE**));
public void Set(Tuple<string, Type> key, object value)
{
if(value.GetType() != SettingsName.Value)
throw new ArgumentException("value");
}
}
You would be better of using generics like in the other answers though.
I don't think you need to deal with Types at all. Would something like this be good enough?
class Settings {
public static int Foo {
get { return (int)_map["Foo"]; }
set { _map["Foo"] = value; }
}
public static string Bar {
get { return (string)_map["Foo"]; }
set { _map["Foo"] = value; }
}
// ...
private static Dictionary<string, object> _map =
new Dictionary<string, object>();
}
You'd then serialize the dictionary. You could even use some code-generation to create this class.

Categories