I want to implement same simple generic conversion method but on runtime I am getting an error.
So the scenario is quite simple. I have same service that return me list of items of type External. I have my own WrapperExternal class that simply wrap this class and expose some additional functionality to it. I have some another set of classes that inherit from WrapExternal and add different functionalities.
I want to create generic method that accept list of External list items and return list of items of specified type.
My application code:
static void Main(string[] args)
{
var items = GetItemsFromServer();
var converted = ConvertItems<SubWrapperExternal>(items).ToList();
}
public static IEnumerable<T> ConvertItems<T>(IEnumerable<External> externalItems) where T : WrapperExternal
{
return externalItems
.Where( item => true)
.Select(item => (T)item);
}
When you try to run this code you will get exception in line (T)item:
An unhandled exception of type 'System.InvalidCastException' occurred in ConsoleApplication1.exe
Additional information:
Unable to cast object of type 'ConsoleApplication1.WrapperExternal' to type 'ConsoleApplication1.SubWrapperExternal'.
Do you know how can I make it to works?
Test application code:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var items = GetItemsFromServer();
var converted = ConvertItems<SubWrapperExternal>(items).ToList();
}
private static List<External> GetItemsFromServer()
{
return new List<External>
{
new External{Name = "A"},
new External{Name = "B"},
new External{Name = "C"},
};
}
public static IEnumerable<T> ConvertItems<T>(IEnumerable<External> externalItems) where T : WrapperExternal
{
return externalItems
.Where( item => true)
.Select(item => (T)item);
}
}
class External
{
public string Name { get; set; }
}
class WrapperExternal
{
public External External { get; private set; }
public WrapperExternal(External external)
{
External = external;
}
public static explicit operator WrapperExternal(External item)
{
return item != null ? new WrapperExternal(item) : null;
}
public static implicit operator External(WrapperExternal item)
{
return item != null ? item.External : null;
}
}
class SubWrapperExternal : WrapperExternal
{
public SubWrapperExternal(External external)
: base(external)
{
}
public static explicit operator SubWrapperExternal(External item)
{
return item != null ? new SubWrapperExternal(item) : null;
}
public static implicit operator External(SubWrapperExternal item)
{
return item != null ? item.External : null;
}
}
}
Conversion operators are a faff to use with generics - generics don't support any static operator overloads. Because of this, the (T) cast is performing a non-converting type check (generics need to use the same IL for every possible T, remember) - a basic castclass.
The only "simple" way of doing what you want is to cheat with dynamic:
return externalItems.Select(item => (T)(dynamic)item);
Since the C#-specific dynamic provider knows all the common rules of C#, it knows about conversion operators, and will apply them on-demand. There is a slight performance cost associated with this, but it isn't as bad as it looks at first glance, as the strategy is cached (as IL) once per type - it doesn't perform per-item reflection.
Related
How can I convert these two ConvertDtoListToAddresses and ConvertDtoListToDocuments C# methods to a generic? I've tried passing in two generic type variables, but when I get down to 'Add' in the loop I get stuck on various errors. Converting from a DTO to its respective DBO is done in the constructor of the DBO, which I think is part of the problem.
private void ConvertDtoToPerson(PersonDTO dto)
{
Id = dto.Id;
Fname = dto.FirstName;
Mname = dto.MiddleName;
Lname = dto.LastName;
Suffix = dto.Suffix;
Maiden = dto.MaidenName;
Addresses = ConvertDtoListToAddresses(dto.AddressesDto); // want to convert to generic
Documents = ConvertDtoListToDocuments(dto.DocumentsDto); // want to convert to generic
}
private static ICollection<Address>? ConvertDtoListToAddresses(ICollection<AddressDTO>? addressesDto)
{
if (addressesDto is not null && addressesDto.Any())
{
ICollection<Address> addys = new List<Address>();
foreach (AddressDTO dto in addressesDto)
{
// Converts from dto in constructor
addys.Add(new Address(dto));
}
return addys;
}
return null;
}
private static ICollection<Document>? ConvertDtoListToDocuments(ICollection<DocumentDTO>? documentsDto)
{
if (documentsDto is not null && documentsDto.Any())
{
ICollection<Document> docs = new List<Document>();
foreach (DocumentDTO dto in documentsDto)
{
// Converts from dto in constructor
docs.Add(new Document(dto));
}
return docs;
}
return null;
}
Here is what I tried:
Addresses = ConvertDtoListToType<Address, AddressDTO>(dto.AddressesDto);
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection)
{
if (dtoCollection is not null && dtoCollection.Any())
{
ICollection<T> tList = new List<T>();
foreach (D dto in dtoCollection)
{
tList.Add(new T(dto)); // <-- This is where I'm having trouble
}
return tList;
}
return null;
}
Use of a Func<D, T> factory parameter would sort this out.
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection, Func<D, T> factory)
{
if (dtoCollection is not null && dtoCollection.Any())
{
ICollection<T> tList = new List<T>();
foreach (D dto in dtoCollection)
{
tList.Add(factory(dto));
}
return tList;
}
return null;
}
Do keep in mind that that is almost the semantic equivalent of this:
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection, Func<D, T> factory)
=> dtoCollection?.Select(d => factory(d))?.ToList();
I'd question the idea that an empty dtoCollection should return a null final collection anyway. This is probably a better implementation.
So, having said that, your original method offers very little functionality benefit. It's code for code's sake. A simple Select/ToList pair keeps your code simple.
In any case, you can provide a static method off of Address and Document to provide the Func<D, T> that you need.
public class Address
{
AddressDTO dto;
public static Address CreateFromDto(AddressDTO dto)
=> new Address(dto);
public Address(AddressDTO dto)
{
this.dto = dto;
}
}
Now, calling it is like this:
var addresses = ConvertDtoListToType(addressDtos, Address.CreateFromDto);
Or:
var addresses = addressDtos?.Select(Address.CreateFromDto)?.ToList();
What you need is to be able to provide a constraint on the Type T to say that it has a constructor that takes a parameter of type D. Something like this:
private static ICollection<T>? ConvertDtoListToType<T, D>(
ICollection<D>? dtoCollection) where T : new(D)
{}
But this does not exist in C#. The workaround is to provide a factory method to create your type T given a type D. i.e. Something like:
private static ICollection<T>? ConvertDtoListToType<T, D>(
ICollection<D>? dtoCollection, Func<D, T> factory)
{
// Use factory(dto), instead of new T(dto)
}
But as #Zee says, you should have a look at Automapper, which can convert between types of collections.
I am currently creating a custom way of deep-copying my objects. I use a static class for this functionality.
public static class CopyServer
{
public static int CopyDeep(int original)
{
return original;
}
//not shown: same for all other value types I use (long, float,...)
public static T CopyDeep<T>(T original) where T: ICopyAble
{
if (original == null)
return default;
if (original is ICopyAutofields)
return CopyAutofields(original);
return (T)original.CopyDeep();
}
private static T CopyAutofields<T>(T original)
{
Delegate del;
if (!_copyFunctions.TryGetValue(typeof(T), out del))
{
//not shown: Building expression for parameter etc.
foreach (var fieldInfo in typeof(T).GetFields())
{
//not shown: checking options set by custom attributes
MethodInfo methodInfo = typeof(CopyServer).GetMethod("CopyDeep", new[] { fieldInfo.FieldType });
//I can't remove the second param without getting an AmbiguousMatchException
if (methodInfo == null)
{
throw new Exception($"CopyDeep not defined for type {fieldInfo.FieldType}");
}
if (methodInfo.IsGenericMethod)
methodInfo = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
Expression call = Expression.Call(methodInfo, readValue);
//not shown: Assign Expression
}
//not shown: return Expression and compiling
}
return ((Func<T, T>)del)(original);
}
}
I use T CopyAutofields<T> to build functions (by building and compiling Expression Trees) so I don't have to create copy-functions for each and every class I want to copy by hand. I control the copy-behaviour with Custom Attributes (I left this part in the code above since it is not relevant for my problem).
The code works fine as long as long as only fields with types for which a non-generic function exists are used. But it is not able to retrieve my generic function T CopyDeep<T>.
Example:
//This works:
public class Manager : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
}
//This doesn't
//Meaning: typeof(CopyServer).GetMethod("copyDeep", new[] { fieldInfo.FieldType });
//in T copyAutofields<T> returns null for the Manager-field and my exception gets thrown
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
}
//This is what I was using before I started using the ICopyAutofields.
//This approach works, but its' too much too write since my classes usually
//have way more than three fields and I occasionally forget to update
//copyDeep()-function if I add new ones.
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
public IModable CopyDeep()
{
var result = new Employee();
result.FirstName = CopyServer.copyDeep(FirstName);
result.LastName= CopyServer.copyDeep(LastName);
result.Manager= CopyServer.copyDeep(Manager);
return result;
}
}
Long story short: I need a way of getting a matching function for a type T if both generic and non-generic functions with the right name exist.
In .NET 4.7.1 you need to use method GetMethods and filter the results:
class MyClass
{
public T M<T>(T t) { return default(T); }
public int M(int t) { return 0; }
}
var m = typeof(MyClass).GetMethod("M", new[] { typeof(string) }); // null
var m1 = typeof(MyClass).GetMethods()
.Where(mi => mi.Name == "M" && mi.GetGenericArguments().Any())
.First(); // returns generic method
In .NET Standard 2.1 (and .NET Core since 2.1) there is another way to resolve generic type arguments - Type.MakeGenericMethodParameter, like you can see it in this answer.
Also as workaround you can move your copyAutofields<T> method to generic class like CopyAutoFieldServer<T>:
public static class CopyAutoFieldServer<T>
{
public static T copyAutofields(T original) { ... }
}
Currently we implement a mapping service like this (the service uses automapper, and we make use of the projection feature on it for this part)
// Injected
// IGenericRepository<Entity> entityRepo
var query = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1);
var result = this.mappingService
.Map<Entity, EntityDto>(query)
.FirstOrDefault();
I'd like to create an extension that would allow me to do the following
var result = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1).Map<EntityDto>() <--- Entity inferred from repo type
.FirstOrDefault();
My current attempt:
public static class IQueryableExtensions
{
private static IMappingService mappingService;
// will need to be called in app initialization
public static void InitialiseMapper(IMappingService service)
{
mappingService = service;
}
public static IEnumerable<TDto> Map<TAttribute, TDto>(this IQueryable<TAttribute> value)
where TDto : class
where TAttribute : IEntity
{
return mappingService.Map<TAttribute, TDto>(value);
}
}
Thus currently my implementation would look like this.
var result = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1).Map<Entity,EntityDto>()
.FirstOrDefault();
Questions:
1) How would i go about inferring the entity type from the IQueryable object
2) I realize i cant create a constructor that takes parameters, when creating a static class. Is the way i init the mapper the best/only way?
I tried that with reflection. The constraints are only for demo. If you want to call the reflection code multiple times be sure to cache the final methodinfo.
void Main()
{
var a = new Entity[] {new Entity { name = "a"},new Entity { name = "b"}};
Console.WriteLine(a.Take(1).Map<EntityDto>());
}
public class Entity
{
public string name;
}
public class EntityDto
{
public string dtoname;
}
public static class EntityExtensions
{
public static IEnumerable<U> Map<T,U>(this IEnumerable<T> e) where T: Entity where U: EntityDto, new()
{
foreach(var a in e)
{
yield return new U() { dtoname = a.name };
}
}
public static IEnumerable<U> Map<U>(this IEnumerable<object> e)
{
var method = typeof(EntityExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Map" && m.GetGenericArguments().Length == 2)
.Single();
method = method.MakeGenericMethod(e.GetType().GetGenericArguments()[0], typeof(U));
return method.Invoke(null, new object[] { e}) as IEnumerable<U>;
}
}
1) Currently, you simply can't do that in C#. The type inference is not good enough. You can either specify all type parameters or none of them.
Edit: If you really want the version with a single parameter, you have to delete the second type parameter, type the parameter as non-generic IQueryable and deal with it. One way of doing that would be to determine the generic IQueryable<T> type at runtime. However, this requires reflection. In the case of IQueryable, you can also use the query provider to get around the reflection.
2) You can use a static type constructor.
public static class MyExtensions {
static MyExtensions() {
//initialization goes here
}
}
This type constructor is even called thread-safe. However, if you manage to throw an exception here, you cannot access the MyExtensionsclass!
Java 1.8 is receiving the Optional<T> class, that allows us to explicitly say when a method may return a null value and "force" its consumer to verify if it is not null (isPresent()) before using it.
I see C# has Nullable<T>, that does something similar, but with basic types. It seems to be used for DB queries, to distinguish when a value exists and is 0 from when it doesn't exist and is null.
But it seems that C#'s Nullable<T>doesn't work for objects, only for basic types, while Java's Optional<T> only works for objects and not for basic types.
Is there a Nullable/Optional class in C#, that forces us to test if object exists before extracting and using it?
Not in the language, no, but you can make your own:
public struct Optional<T>
{
public bool HasValue { get; private set; }
private T value;
public T Value
{
get
{
if (HasValue)
return value;
else
throw new InvalidOperationException();
}
}
public Optional(T value)
{
this.value = value;
HasValue = true;
}
public static explicit operator T(Optional<T> optional)
{
return optional.Value;
}
public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
public override bool Equals(object obj)
{
if (obj is Optional<T>)
return this.Equals((Optional<T>)obj);
else
return false;
}
public bool Equals(Optional<T> other)
{
if (HasValue && other.HasValue)
return object.Equals(value, other.value);
else
return HasValue == other.HasValue;
}
}
Note that you won't be able to emulate certain behaviors of Nullable<T>, such as the ability to box a nullable value with no value to null, rather than a boxed nullable, as it has special compiler support for that (and a some other) behavior.
In my opinion, any Option implementation which exposes HasValue property is the defeat of the entire idea. The point of optional objects is that you can make unconditional calls to their contents without testing whether the content is there.
If you have to test whether the optional object contains a value, then you have done nothing new compared to common null tests.
Here is the article in which I am explaining optional objects in full detail: Custom Implementation of the Option/Maybe Type in C#
And here is the GitHub repository with code and examples: https://github.com/zoran-horvat/option
If you're reluctant to use a heavyweight Option solution, then you can easily build a lightweight one. You can make your own Option<T> type which implements IEnumerable<T> interface, so that you can leverage LINQ extension methods to turn calls optional. Here is the simplest possible implementation:
public class Option<T> : IEnumerable<T>
{
private readonly T[] data;
private Option(T[] data)
{
this.data = data;
}
public static Option<T> Create(T value)
{
return new Option<T>(new T[] { value });
}
public static Option<T> CreateEmpty()
{
return new Option<T>(new T[0]);
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)this.data).GetEnumerator();
}
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return this.data.GetEnumerator();
}
}
Using this Option<T> type is done via LINQ:
Option<Car> optional = Option<Car>.Create(myCar);
string color = optional
.Select(car => car.Color.Name)
.DefaultIfEmpty("<no car>")
.Single(); // you can call First(), too
You can find more about optional objects in these articles:
Custom Implementation of the Option/Maybe Type in C#
Understanding the Option (Maybe) Functional Type
How to Reduce Cyclomatic Complexity: Option Functional Type
And you may refer to my video courses for more details on how to simplify control flow using Option type and other means: Making Your C# Code More Functional and
Tactical Design Patterns in .NET: Control Flow
The first video course (Making Your C# Code More Functional) brings detailed introduction to railway-oriented programming, including the Either and Option types and how they can be used to manage optional objects and handle exceptional cases and errors.
There is better implementation of option type in C#. You can find this implemenation in Tactical design patterns in .NET by Zoran Horvat at pluralsight.com. It includes an explanation why and how to use it. The basic idea is to implement option class as implementation of IEnumerable<> interface.
public class Option<T> : IEnumerable<T>
{
private readonly T[] data;
private Option(T[] data)
{
this.data = data;
}
public static Option<T> Create(T element)
{
return new Option<T>(new[] { element });
}
public static Option<T> CreateEmpty()
{
return new Option<T>(new T[0]);
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>) this.data).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
In the project "C# functional language extensions" https://github.com/louthy/language-ext
exists the Option object of F# among others functional patters
Instead of writing your own class, you could use Microsoft.FSharp.Core.FSharpOption<T> from the FSharpCore.dll assembly. Unfortunately, the F# types are a bit clumsy when used in C#.
//Create
var none = FSharpOption<string>.None;
var some1 = FSharpOption<string>.Some("some1");
var some2 = new FSharpOption<string>("some2");
//Does it have value?
var isNone1 = FSharpOption<string>.get_IsNone(none);
var isNone2 = OptionModule.IsNone(none);
var isNone3 = FSharpOption<string>.GetTag(none) == FSharpOption<string>.Tags.None;
var isSome1 = FSharpOption<string>.get_IsSome(some1);
var isSome2 = OptionModule.IsSome(some1);
var isSome3 = FSharpOption<string>.GetTag(some2) == FSharpOption<string>.Tags.Some;
//Access value
var value1 = some1.Value; //NullReferenceException when None
var value2 = OptionModule.GetValue(some1); //ArgumentException when None
There's nothing built-in, but you can define your own. Note that an Option<T> implementation doesn't make sense without defining the map/bind operators.
public struct Option<T>
{
private bool hasValue;
private T value;
public Option(T value)
{
if (value == null) throw new ArgumentNullException("value");
this.hasValue = true;
this.value = value;
}
public Option<TOut> Select<TOut>(Func<T, TOut> selector)
{
return this.hasValue ? new Option<TOut>(selector(this.value)) : new Option<TOut>();
}
public Option<TOut> SelectMany<TOut>(Func<T, Option<TOut>> bind)
{
return this.hasValue ? bind(this.value) : new Option<TOut>();
}
public bool HasValue
{
get { return this.hasValue; }
}
public T GetOr(T #default)
{
return this.hasValue ? this.value : #default;
}
}
Perhaps this is closer to the F# Option type
public struct Option<T>
{
private T value;
private readonly bool hasValue;
public bool IsSome => hasValue;
public bool IsNone => !hasValue;
public T Value
{
get
{
if (!hasValue) throw new NullReferenceException();
return value;
}
}
public static Option<T> None => new Option<T>();
public static Option<T> Some(T value) => new Option<T>(value);
private Option(T value)
{
this.value = value;
hasValue = true;
}
public TResult Match<TResult>(Func<T, TResult> someFunc, Func<TResult> noneFunc) =>
hasValue ? someFunc(value) : noneFunc();
public override bool Equals(object obj)
{
if (obj is Option<T>)
{
var opt = (Option<T>)obj;
return hasValue ? opt.IsSome && opt.Value.Equals(value) : opt.IsNone;
}
return false;
}
public override int GetHashCode() =>
hasValue ? value.GetHashCode() : 0;
}
I decided to implement some kind of Optional<> Java class prototype some time ago using one of the last C# version.
Here it is:
public sealed class Optional<T>
{
private static readonly Optional<T> EMPTY = new Optional<T>();
private readonly T value;
private Optional() => value = default;
private Optional(T arg) => value = arg.RequireNonNull("Value should be presented");
public static Optional<T> Empty() => EMPTY;
public static Optional<T> Of(T arg) => new Optional<T>(arg);
public static Optional<T> OfNullable(T arg) => arg != null ? Of(arg) : Empty();
public static Optional<T> OfNullable(Func<T> outputArg) => outputArg != null ? Of(outputArg()) : Empty();
public bool HasValue => value != null;
public void ForValuePresented(Action<T> action) => action.RequireNonNull()(value);
public IOption<T> Where(Predicate<T> predicate) => HasValue
? predicate.RequireNonNull()(value) ? this : Empty() : this;
public IOption<TOut> Select<TOut>(Func<T, TOut> select) => HasValue
? Optional<TOut>.OfNullable(select.RequireNonNull()(value))
: Optional<TOut>.Empty();
public IOption<IOption<TOut>> SelectMany<TOut>(Func<T, IOption<TOut>> select) => HasValue
? Optional<IOption<TOut>>.OfNullable(select.RequireNonNull()(value))
: Optional<IOption<TOut>>.Empty();
public T Get() => value;
public T GetCustomized(Func<T, T> getCustomized) => getCustomized.RequireNonNull()(value);
public U GetCustomized<U>(Func<T, U> getCustomized) => getCustomized.RequireNonNull()(value);
public T OrElse(T other) => HasValue ? value : other;
public T OrElseGet(Func<T> getOther) => HasValue ? value : getOther();
public T OrElseThrow<E>(Func<E> exceptionSupplier) where E : Exception => HasValue ? value : throw exceptionSupplier();
public static explicit operator T(Optional<T> optional) => OfNullable((T) optional).Get();
public static implicit operator Optional<T>(T optional) => OfNullable(optional);
public override bool Equals(object obj)
{
if (obj is Optional<T>) return true;
if (!(obj is Optional<T>)) return false;
return Equals(value, (obj as Optional<T>).value);
}
public override int GetHashCode() => base.GetHashCode();
public override string ToString() => HasValue ? $"Optional has <{value}>" : $"Optional has no any value: <{value}>";
}
Use T? nullable reference instead of Option<T>
Since C#8 you should deprecate custom Option<T>-implementations. The null dilemma is now completely resolved.
T? is a complete substitution for Option<T>
C# has the following features for handling null:
Null coalescing operator
Null conditional operator
Non nullable & nullable reference types (since C#8)
Configurable compile errors/warnings
Keep in mind that
Option<Car> optional = Option<Car>.Create(myCar);
string color = optional
.Select(car => car.Color.Name)
.DefaultIfEmpty("<no car>")
.Single(); // you can call First(), too
is the same as
string color = myCar?.Color.Name ?? "<no car>";
and additionally the string color is also a reference that can't be null.
If you don't like baking your own solutions, I would use Language Ext. It is available on nuget. I have recently started using this library, and the safety from null references is amazing! I am not a expert with this library, but it can do what you are asking for, and much more.
Here is a taste of what can be done:
using System;
using LanguageExt;
using static LanguageExt.Prelude;
public class Demo
{
public static Option<int> ToEvenOrNone(int i) =>
i % 2 == 0
? i.Apply(Optional)
: None;
public static void PrintToDebug(Option<int> value) =>
value
.Some(Console.WriteLine)
.None(() => Console.WriteLine("Value is not Even!"));
public static void Test()
{
for (int i = 0; i < 10; i++)
{
PrintToDebug(ToEvenOrNone(i));
}
}
}
Here is the output:
0
Value is not Even!
2
Value is not Even!
4
Value is not Even!
6
Value is not Even!
8
Value is not Even!
Is there a Nullable/Optional class in C#, that forces us to test if
object exists before extracting and using it?
Nullables were created so that primitive types could be null. Their default value didn't have to be an actual value (Like int, without nullables it's default is 0, so is that a 0 means something 0 or a not set to anything 0?)
No there is nothing that you can do to force a programmer to check if an object is null. That's good though. Doing so would create an immense amount of overhead. If this was a language feature, how often would you force check? Would you require it when the variable is first assigned? What if the variable points to another object later? Would you force it to check before every method and property, and if it fails would you throw an exception? You get that now with a null reference exception. You would get very little benefit in forcing someone to do this beyond what you already have.
Learned a lot from Zoran Horvat's answer. Here is my code. optional can has a real value or an empty. On the consuming side, same code handle them all.
void Main()
{
var myCar = new Car{ Color = Color.Black, Make="Toyota"};
Option<Car> optional = Option<Car>.Create(myCar);
// optional is an Empty 50% of the time.
if(new Random().NextDouble() > 0.5)
optional = Option<Car>.CreateEmpty();
string color = optional
.Select(car => car.Color.Name)
.DefaultIfEmpty("<no car>")
.Single();
Console.Write(color);
}
class Car {
public Color Color { get; set; }
public string Make { get; set;}
}
public class Option<T> : IEnumerable<T>
{
private readonly T[] data;
private Option(T[] data)
{
this.data = data;
}
public static Option<T> Create(T value)
{
return new Option<T>(new T[] { value });
}
public static Option<T> CreateEmpty()
{
return new Option<T>(new T[0]);
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)this.data).GetEnumerator();
}
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return this.data.GetEnumerator();
}
}
https://github.com/mcintyre321/OneOf
I thought this oneOf class had a good re-creation of option type. It even includes a .switch/.match with pattern matching, and most importantly it works at runtime which is what you expect out of an Option pattern.
The below code is a factory class that is delivers objects of type IGraph that have the GraphTypeAttribute implemented. Inside the static constructor of the GraphFactory, a list is built by using Linq to collect the appropriate classes to be delivered by the Factory. Normally without Linq I had a buch of loops and if-then's that could be wrapped easily with appropriate try-catch blocks. Since all is stuffed in one query now I am a bit confused on how to implement proper exceptionhandling here.
So my question(s) is/are
What is the best pattern to handle exceptions on the linq query.
Should I split it in different queries or not use linq at all?
Or am I mising something in the query that can eliminate non-existing elements, scanning wrong classes etc, querying duplicate values etc (optimizing the query ;).
The result of the query must be a list of all classes that the factory can deliver. E.g. decorated with the attribute and the interface implemented.
A "Factory" that creates objects for graphical representation of data:
public sealed class GraphFactory
{
static readonly GraphFactory _instance = new GraphFactory();
static readonly IDictionary<string, Type> _items;
static readonly Assembly _assembly = Assembly.GetExecutingAssembly();
public static GraphFactory Instance { get { return _instance; } }
GraphFactory() { }
static GraphFactory() {
try
{
_items = (from type in _assembly.GetTypes()
// filter from thatonly the classes with IGraph implemented
where type.GetInterface(typeof(IGraph).FullName) != null
// filter from thatonly the classes with GraphTypeAttribute imp.
from attribute in type.GetCustomAttributes(true)
where attribute is GraphTypeAttribute
select new { attribute, type })
// convert the result from anonymous to a dictionary
.ToDictionary(k => (k.attribute as GraphTypeAttribute).CustomType,
e => e.type);
}
/** EXH: non pokemon exception handling * ........... * **/
}
public static IEnumerable<string> FriendlyNames { get { return _items.Keys; } }
public static IGraph CreateGraph(string friendlyName)
{
/** inspect argument, check it's a key
in the dictionary and throw exeptions if needed **/
IGraph result = null;
try
{
result = _assembly.CreateInstance(_items[friendlyName].FullName) as IGraph;
}
/** non pokemon exception handling * ........... * **/
return result;
}
}
the interface (members ommitted):
public interface IGraph { }
attribute to decorate the appropriate classes for factory assigment
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false,Inherited=true)]
public class GraphTypeAttribute : System.Attribute
{ public GraphTypeAttribute(string friendlyName) { } }
the classes decorated with the attribute
[GraphTypeAttribute("piechart")]
public class PieChart : IGraph{ }
[GraphTypeAttribute("map")]
public class WorldMap : IGraph { }
[GraphTypeAttribute("horizontalbar")]
public class Bar : IGraph { }
[GraphTypeAttribute("verticalbar")]
public class VerticalBar : Bar { }
sample usage:
foreach (string friendlyName in GraphFactory.FriendlyNames)
{
IGraph auth = GraphFactory.CreateGraph(friendlyName);
}
Any other comments or advise on the class is thankfully appreciated.
I think this is a good example of the dynamic factory pattern. I do this all the time. I understand your concern about exception handling but I think there is no need for this, simply because your unit tests will prevent this factory from ever throwing during production and a good unit test can explain as clearly the problem as an exception message.
But if you really want to do error checking, your LINQ query will never throw an exception. It is the ToDictionary that will throw when there is a double key. What you can do is validate the results of the LINQ query and communicate the double keys:
static GraphFactory()
{
var items = (
from type in _assembly.GetTypes()
where type.GetInterface(typeof(IGraph).FullName) != null
from attribute in type.GetCustomAttributes(true)
.OfType<GraphTypeAttribute>
select new { attribute, type }).ToArray();
ValidateTypes(items);
_item = items.ToDictionary(
k => k.attribute.CustomType, e => e.type);
}
private static void ValidateTypes<T>(T[] items)
{
var firstDoubleCustomType = (
from item in items
group item by item.attribute.CustomType into g
where g.Count() > 1
select g.Key).FirstOrDefault();
if (firstDoubleCustomType != null)
{
throw new InvalidProgramException(
"Doube: " + firstDoubleCustomType.ToString());
}
}