So I am using Simple.Mocking to Mock some interfaces on my tests. Some methods receive custom objects
public class MyObj
{
public int Attr { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as MyObj);
}
public override int GetHashCode()
{
return Attr;
}
private bool Equals(MyObj myObj)
{
return Attr == myObj.Attr;
}
}
public interface IFoo
{
void Show(MyObj o);
}
public class ObjUnderTest
{
public ObjUnderTest(IFoo foo)
{
var o = new MyObj{ Attr = 1; };
foo.Show(o);
}
}
[TestClass]
public class TestClasse
{
[TestMethod]
public void TestShow()
{
var foo = Mock.Interface<IFoo>();
var myObj = new MyObj { Attr = 1 };
Expect.Once.MethodCall(() => foo.Show(myObj));
var objectUnderTest = new ObjUnderTest(foo);
AssertExpectations.IsMetFor(foo);
}
}
The problems is that test fails always, even when Show is called with a object with Attrequals to 1. It only pass if I write the expect like this:
Expect.Once.MethodCall(()=> foo.Show(Any<MyObj>.Value));
Which is not what I need. I know it fails because those are different objects but I have tried overriding MyObj Equals and GetHashCode with no success.
Any Ideas?
If the desired outcome is to validate the input you can try specifying exptectation with a predicate
Expect.Once.MethodCall(()=> foo.Show(Any<MyObj>.Value.Matching(obj => obj.Attr == 1)));
Source: project readme on Github - Using "wildcard" parameter values
[TestClass]
public class TestClasse {
[TestMethod]
public void TestShow() {
//Arrange
var foo = Mock.Interface<IFoo>();
Expect.Once.MethodCall(()=> foo.Show(Any<MyObj>.Value.Matching(obj => obj.Attr == 1)));
//Act
var objectUnderTest = new ObjUnderTest(foo);
//Assert
AssertExpectations.IsMetFor(foo);
}
}
Related
I am making generic validators for checking input:
Interface:
public interface IInputValidator
{
bool CanHandle<T>();
bool Validate<T>(string? input, out T result);
}
Implementation:
public class IntegerValidator : IInputValidator
{
public bool CanHandle<T>()
{
return typeof(T) == typeof(int);
}
public bool Validate<T>(string? input, out T result)
{
var isValid = int.TryParse(input, out var res);
result = (T)(object)res;
return isValid;
}
}
Then I grab all the validators I have and inject like so: (it feels convenient that the interface itself is not generic thus I don't have to inject them one by one and able to group them in a single collection)
private readonly IEnumerable<IInputValidator> _inputValidators;
public CallerClass(IEnumerable<IInputValidator> inputValidators)
{
_inputValidators = inputValidators;
}
And call it like:
var validator = _inputValidators.First(r => r.CanHandle<int>());
var isInputValid = validator.Validate(userInput, out int id);
It all looks fine except for this line in implementation
result = (T)(object)res;
I feel like something is wrong here but can't figure out how to make it better. It works like this though.
The core issue is that you are trying to combine the resolution of the appropriate validator and the action of that validator into the same generic interface.
If you are willing to separate the resolver and validator functionality into two interfaces:
public interface IInputValidatorResolver
{
bool CanHandle<T>();
IInputValidator<T> GetValidator<T>();
}
public interface IInputValidator<T>
{
bool Validate(string? input, out T result);
}
you can work with IInputValidatorResolver instances in your CallerClass contract to instead resolve the appropriate validator and strongly-type you call to the validator without an object cast. The resolver implementations can create a cache that casts your Validator to a generic IInputValidator<T> instance.
public class IntegerValidatorResolver : IInputValidatorResolver
{
public bool CanHandle<T>() => typeof(T) == typeof(int);
public IInputValidator<T> GetValidator<T>() => Cache<T>.Validator;
private static class Cache<T>
{
public static readonly IInputValidator<T> Validator = BuildValidator();
private static IInputValidator<T> BuildValidator() => ((IInputValidator<T>)new IntegerValidator());
}
}
public class LongValidatorResolver : IInputValidatorResolver
{
public bool CanHandle<T>() => typeof(T) == typeof(long);
public IInputValidator<T> GetValidator<T>() => Cache<T>.Validator;
private static class Cache<T>
{
public static readonly IInputValidator<T> Validator = BuildValidator();
private static IInputValidator<T> BuildValidator() => ((IInputValidator<T>)new LongValidator());
}
}
public class IntegerValidator : IInputValidator<int>
{
public bool Validate(string? input, out int result) => int.TryParse(input, out result);
}
public class LongValidator : IInputValidator<long>
{
public bool Validate(string? input, out long result) => long.TryParse(input, out result);
}
and you can test it with the following:
IEnumerable<IInputValidatorResolver> validatorResolvers = new List<IInputValidatorResolver> { new IntegerValidatorResolver(), new LongValidatorResolver() };
var intValidator = validatorResolvers.First(x => x.CanHandle<int>()).GetValidator<int>();
var isIntValid = intValidator.Validate(long.MaxValue.ToString(), out int intResult);
Console.WriteLine(isIntValid);
Console.WriteLine(intResult);
var longValidator = validatorResolvers.First(x => x.CanHandle<long>()).GetValidator<long>();
var isLongValid = longValidator.Validate(long.MaxValue.ToString(), out long longResult);
Console.WriteLine(isLongValid);
Console.WriteLine(longResult);
That said, this creates an awkward contract where if you do NOT perform a check with CanHandle<T> first, your call to GetValidator<T> can throw an exception. In addition, in either this implementation or your current implementation, you have to loop through resolvers/validators to find the appropriate instance, which is unnecessarily wasteful.
As a result, it may make more sense to have a single IInputValidatorResolver instance that knows how to resolve the appropriate validator based on the type of T, without a CanHandle<T>() check.
public interface IInputValidatorResolver
{
IInputValidator<T> GetValidator<T>();
}
public class ValidatorResolver : IInputValidatorResolver
{
public IInputValidator<T> GetValidator<T>() => Cache<T>.Validator;
private static class Cache<T>
{
public static readonly IInputValidator<T> Validator = BuildValidator();
private static IInputValidator<T> BuildValidator()
{
if (typeof(T) == typeof(int))
{
return ((IInputValidator<T>)new IntegerValidator());
}
else if (typeof(T) == typeof(long))
{
return ((IInputValidator<T>)new LongValidator());
}
else
{
throw new ArgumentException($"{typeof(T).FullName} does not have a registered validator.");
}
}
}
}
public interface IInputValidator<T>
{
bool Validate(string? input, out T result);
}
public class IntegerValidator : IInputValidator<int>
{
public bool Validate(string? input, out int result) => int.TryParse(input, out result);
}
public class LongValidator : IInputValidator<long>
{
public bool Validate(string? input, out long result) => long.TryParse(input, out result);
}
This allows for a much cleaner API and far less registration and enumeration:
IInputValidatorResolver resolver = new ValidatorResolver();
var intValidator = resolver.GetValidator<int>();
var isIntValid = intValidator.Validate(long.MaxValue.ToString(), out int intResult);
Console.WriteLine(isIntValid);
Console.WriteLine(intResult);
var longValidator = resolver.GetValidator<long>();
var isLongValid = longValidator.Validate(long.MaxValue.ToString(), out long longResult);
Console.WriteLine(isLongValid);
Console.WriteLine(longResult);
UPDATE
It looks like you want a purely constructor-injection driven solution. You can accomplish this by registering a new interface as IEnumerable<IInputValidator> and injecting it into the resolver instance.
The IInputValidator interface is responsible for the CanHandle<T>() method that is checked prior to casting to IInputValidator<T>.
public interface IInputValidatorResolver
{
IInputValidator<T> GetValidator<T>();
}
public class ValidatorResolver : IInputValidatorResolver
{
private IEnumerable<IInputValidator?> _validators;
public ValidatorResolver(IEnumerable<IInputValidator?> validators)
{
_validators = validators;
}
public IInputValidator<T> GetValidator<T>()
{
foreach (var validator in _validators)
{
if (validator!.CanHandle<T>())
{
return (IInputValidator<T>)validator;
}
}
throw new ArgumentException($"{typeof(T).FullName} does not have a registered validator.");
}
}
public interface IInputValidator
{
bool CanHandle<TInput>();
}
public interface IInputValidator<T> : IInputValidator
{
bool Validate(string? input, out T result);
}
public class IntegerValidator : IInputValidator<int>
{
public bool CanHandle<T>() => typeof(T) == typeof(int);
public bool Validate(string? input, out int result) => int.TryParse(input, out result);
}
public class LongValidator : IInputValidator<long>
{
public bool CanHandle<T>() => typeof(T) == typeof(long);
public bool Validate(string? input, out long result) => long.TryParse(input, out result);
}
You can test this behavior with the following:
var servicesCollection = new ServiceCollection();
servicesCollection.AddTransient(typeof(IEnumerable<IInputValidator>), s =>
{
return new List<IInputValidator>
{
new IntegerValidator(),
new LongValidator()
};
});
servicesCollection.AddTransient<IInputValidatorResolver, ValidatorResolver>();
var serviceProvider = servicesCollection.BuildServiceProvider();
var resolver = serviceProvider.GetService<IInputValidatorResolver>();
var intValidator = resolver.GetValidator<int>();
var isIntValid = intValidator.Validate(long.MaxValue.ToString(), out int intResult);
Console.WriteLine(isIntValid);
Console.WriteLine(intResult);
var longValidator = resolver.GetValidator<long>();
var isLongValid = longValidator.Validate(long.MaxValue.ToString(), out long longResult);
Console.WriteLine(isLongValid);
Console.WriteLine(longResult);
With this approach, you no longer need the ValidationResolver. It is simply a way to encapsulate the logic of GetValidator<T>. You could just as easily inject IEnumerable<IInputValidator> into your consuming classes and perform the cast each time you need to use it.
Another option is to use Autofac's IComponentContext:
using Autofac;
using TransactionStorage.Interface;
namespace TransactionStorage.Core
{
public class InputResolver : IInputResolver
{
private readonly IComponentContext _context;
public InputResolver (IComponentContext context)
{
_context = context;
}
public bool Validate<T>(string? userInput, out T result) where T : struct
{
var validator = _context.Resolve<IInputValidator<T>>();
return validator.Validate(userInput, out result);
}
}
}
I have a abstract class Enumeration which implements the IComparable interface.
public abstract class Enumeration : IComparable
{
[JsonConstructor]
protected Enumeration(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; }
public string Name { get; }
public static implicit operator Enumeration(string name)
{
return GetAll<Enumeration>().FirstOrDefault(i => i.Name == name);
}
public static IEnumerable<TEnumeration> GetAll<TEnumeration>() where TEnumeration : Enumeration
{
var fields = typeof(TEnumeration).GetFields(
BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
return fields.Select(fieldInfo => fieldInfo.GetValue(null)).Cast<TEnumeration>();
}
I have created SampleStatus.cs class which is inherits from Enumeration.cs class.
public class SampleStatus : Enumeration
{
public static readonly SampleStatus Completed = new SampleStatus(1, nameof(Completed));
public static readonly SampleStatus Deleted = new SampleStatus(2, nameof(Deleted));
public SampleStatus(int id, string name) : base(id, name)
{
}
}
I have created unit test class for SampleStatus.cs class.
[TestMethod]
public void TestMethod()
{
// arrange and act
var result = (Enumeration)SampleStatus.GetAll<SampleStatus>().Single(x => x.Id == 1).Name; // output is returning null.
// assert
Assert.AreEqual("Completed", result);
}
When I call GetAll method which is returning null. I have mocked GetAll and Implicit operator method in the above code.
In provided sample GetAll does not return null (if it did - I would get NullReferenceException). Issue with the sample is in the cast to Enumeration. SampleStatus.GetAll<SampleStatus>().Single(x => x.Id == 1).Name results in Completed which you then cast to Enumeration. Since the implicit conversion exists and the base class does not have definition for Completed (Enumeration)"Completed" ends up being null (i.e. GetAll<Enumeration>().FirstOrDefault(i => i.Name == name))).
You can fix it with removing cast for example:
[TestMethod]
public void TestMethod()
{
// arrange and act
var result = SampleStatus.GetAll<SampleStatus>().Single(x => x.Id == 1).Name; // output is returning null.
// assert
Assert.AreEqual("Completed", result);
}
In the code below, I have the "howmanystringasync" method which is calling two others methods. Those two are faked.
The second fake's return does not work because of the ".ToList()".
I usually returns IEnumerable because in some case I want to restrict the caller actions. And sometimes, I ask in input directly a List so a method can do what a List has to offer.
How can I make the test below works ?
var result = await f.AccessTheWebAsync2(web.ToList());
using FakeItEasy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace api.tests.unit
{
public class SpecialString
{
public int IntProperty { get; set; }
public string StringProperty { get; set; }
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
if (ReferenceEquals(this, obj)) return true;
return Equals(obj as SpecialString);
}
public bool Equals(SpecialString other)
{
if (other == null) return false;
return (this.IntProperty == other.IntProperty) && (this.StringProperty == other.StringProperty);
}
}
public interface IFoo
{
Task<IEnumerable<SpecialString>> AccessTheWebAsync(int a, int b);
Task<int> AccessTheWebAsync2(List<SpecialString> integers);
}
public class Foo : IFoo
{
public async Task<IEnumerable<SpecialString>> AccessTheWebAsync(int a, int b)
{
HttpClient client = new HttpClient();
string result = await client.GetStringAsync("https://msdn.microsoft.com");
var results = new List<SpecialString> {
new SpecialString{
IntProperty = 1,
StringProperty = "stringprop1"
},
new SpecialString{
IntProperty =2,
StringProperty = "stringprop2"
}
};
return results;
}
public async Task<int> AccessTheWebAsync2(List<SpecialString> specialstrings)
{
HttpClient client = new HttpClient();
string result = await client.GetStringAsync("https://msdn.microsoft.com");
var results = new List<SpecialString> {
new SpecialString{
IntProperty = 1,
StringProperty = "stringprop1"
},
new SpecialString{
IntProperty =2,
StringProperty = "stringprop2"
}
};
return results.Count();
}
}
public class BiggerFoo
{
private readonly IFoo f;
public BiggerFoo(IFoo f)
{
this.f = f;
}
public async Task<int> howManyStringsAsync(int a, int b)
{
var web = await f.AccessTheWebAsync(a, b);
var result = await f.AccessTheWebAsync2(web.ToList());
return result;
}
}
public class FooTest
{
[Fact]
public void testasyncmethod()
{
var fakeFoo = A.Fake<IFoo>();
IEnumerable<SpecialString> result = new List<SpecialString> {
new SpecialString{
IntProperty = 1,
StringProperty = "fakestringprop1"
},
new SpecialString{
IntProperty =2,
StringProperty = "fakestringprop2"
}
};
A.CallTo(() => fakeFoo.AccessTheWebAsync(1, 2)).Returns<Task<IEnumerable<SpecialString>>>(Task.FromResult(result));
A.CallTo(() => fakeFoo.AccessTheWebAsync2(result.ToList())).Returns<Task<int>>(Task.FromResult(5));
var bFoo = new BiggerFoo(fakeFoo);
bFoo.howManyStringsAsync(1, 2);
}
}
}
If I read things right, the problem is that you configure AccessTheWebAsync2 to return 5 when given a particular List<SpecialString>, but in your test, the method is called with a different List<SpecialString>, and List<SpecialString>.Equals only does reference equality, so you're getting 0 back. If you want to make sure 5 is returned when a List<SpecialString> containing your desired SpecialStrings is passed to AccessTheWebAsync2, you'll need to adjust the constraint. It looks like SpecialString doesn't have a value-based Equals either, so you could consider examining the elements' properties:
A.CallTo(() => fakeFoo.AccessTheWebAsync(1, 2)).Returns(result);
A.CallTo(() => fakeFoo.AccessTheWebAsync2(
A<List<SpecialString>>.That.Matches(l =>
l.Count == 2 && l[0].IntProperty == 1 && l[1].StringProperty == "fakestringprop2")))
.Returns(5);
Or, if you really don't care about the input value, something like
A.CallTo(() => fakeFoo.AccessTheWebAsync2(A<List<SpecialString>>._))
.Returns(5);
Update: now that you've added SpecialString.Equals, using the list's values as a call matching constraint is easier:
A.CallTo(() => fakeFoo.AccessTheWebAsync2(
A<List<SpecialString>>.That.IsSameSequenceAs(result)))
.Returns(5);
If you haven't already, do check out all of the argument constraints that FakeItEasy provides.
I have multiple data-points and an associated data-processor for each.
public interface IDataPointProcessor<T> where T : DataPointInputBase
{
DataPointOutputBase GetOutput(T input);
}
I load a list of data points from a file and wish to process them using its single associated processor.
foreach (DataPointInputBase item in input.DataPoints)
{
//assuming item coming in is of type 'X' how do I get correct processor
var type = typeof(IDataPointProcessor<X>);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p) && !p.IsAbstract);
IDataPointProcessor<X> matchedType = ??
}
How do I solve for 'X' so I can instantiate it and process the input?
Update #1
Combining answers from below from Slava and Lucky I get the following, but it throws an exception - 'Object does not match target type.' even though it all seems to match up ok in debugger. Is it possible to cast as IDataPointProcessor<> and call interface method cleanly, ie: instance.GetOutput(item);
foreach (DataPointInputBase item in input.DataPoints)
{
Type typeGenArg = item.GetType();
Type typeInterfaceGen = typeof(IDataPointProcessor<>).MakeGenericType(typeGenArg);
Type type = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => typeInterfaceGen.IsAssignableFrom(x) && !x.IsAbstract)
.FirstOrDefault();
Type genericType = typeof(IDataPointProcessor<>);
Type dependedGenericType = genericType.MakeGenericType(typeof(DataPointInputBase));
var method = dependedGenericType.GetMethod("GetOutput");
var instance = Activator.CreateInstance(type);
//currently throws:System.Reflection.TargetException: 'Object does not match target type.'
var result = method.Invoke(instance, new object[] { item });
//Ideally I want to do this and avoid the magic strings etc
//var temp_output = instance.GetOutput(item);
}
Update #2
To keep things moving I've hard coded the type 'Age_Input' to validate the thing works. What am I missing to call the hard coded bit dynamically?
I should be able to cast instance to IDataPointProcessor<IDataPointInput> and call GetOutput() on the interface
foreach (IDataPointInput item in input.DataPoints)
{
Type typeGenArg = item.GetType();
Type typeInterfaceGen = typeof(IDataPointProcessor<>).MakeGenericType(typeGenArg);
Type type = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => typeInterfaceGen.IsAssignableFrom(x) && !x.IsAbstract)
.FirstOrDefault();
Type genericType = typeof(IDataPointProcessor<>);
Type dependedGenericType = genericType.MakeGenericType(typeof(IDataPointInput));
var instance = Activator.CreateInstance(type);
if (instance is IDataPointProcessor<Age_Input>)//hard-coded
{
var processor = instance as IDataPointProcessor<Age_Input>;
Age_Input temp = item as Age_Input;
var result = processor.GetOutput(temp);
}
if (instance is DataPointProcessorBase<DataPointInputBase>)
{
//false
}
if (instance is IDataPointProcessor<DataPointInputBase>)
{
//false
}
if (instance is IDataPointProcessor<IDataPointInput>)
{
//false - shouldn't this work?
}
}
Age_Input is a trivial class, inheriting from a dumb base class and an empty interface
public class Age_Input : DataPointInputBase, IDataPointInput
{
public int AgeExact { get; set; }
}
public class DataPointInputBase : IDataPointInput
{
}
public interface IDataPointInput
{
}
Processor class is similarly simple
public abstract class DataPointProcessorBase<T> : IDataPointProcessor<T> where T : IDataPointInput, new()
{
//public abstract DataPointOutputBase GetOutput(DataPointInputBase input);
public abstract DataPointOutputBase GetOutput(T input);
}
public interface IDataPointInput
{
}
public interface IDataPointProcessor<IDataPointInput>
{
DataPointOutputBase GetOutput(IDataPointInput input);
}
Firstly, you should make covariant your interface like this.
public interface IDataPointProcessor<in T> where T : DataPointInputBase
{
DataPointOutputBase GetOutput(T input);
}
You should retrieve types which is implemented by IDataPointProcessor<>, then you should create the instance of retrieved type and invoke the method of generic type.
Type genericType = typeof(IDataPointProcessor<>);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => genericType.IsAssignableFrom(p) && !p.IsAbstract).ToList();
var dependedGenericType = genericType.MakeGenericType(typeof(DataPointInputBase));
var method = dependedGenericType.GetMethod("GetOutput");
var instance = Activator.CreateInstance(types[0]);
method.Invoke(instance, new object[] { new DataPointInputBase() });
So as is usually the case, if you can avoid Reflection you're generally better off. I traded a tiny bit of code smell for a much simpler solution.
Essentially I went back to basics and used dumb interfaces, and a helper method on the input that returned a primed instance of the corresponding processor.
Now my big reflection loop is replaced with this:
foreach (IDataPointInput item in input)
{
IDataPointProcessor processor = item.GetProcessor();
IDataPointOutput output = processor.GetOutput();
}
The code smell is this - not an issue
public override IDataPointProcessor GetProcessor()
{
return new Age_Processor(this);
}
Full code below
#region Interfaces
public interface IDataPointProcessor
{
IDataPointOutput GetOutput();
}
public interface IDataPointInput
{
IDataPointProcessor GetProcessor();
}
public interface IDataPointOutput
{
List<string> DebugStrings { get; set; }
}
#endregion
#region Base Classes
public abstract class DataPointProcessorBase : IDataPointProcessor
{
public abstract IDataPointOutput GetOutput();
}
public abstract class DataPointInputBase : IDataPointInput
{
public abstract IDataPointProcessor GetProcessor();
}
public abstract class DataPointOutputBase : IDataPointOutput
{
public List<string> DebugStrings { get; set; }
public DataPointOutputBase()
{
DebugStrings = new List<string>();
}
}
#endregion
public class Age_Output : DataPointOutputBase
{
}
public class Age_Input : DataPointInputBase
{
public int AgeExact { get; set; }
public override IDataPointProcessor GetProcessor()
{
return new Age_Processor(this);
}
}
public class Age_Processor : DataPointProcessorBase
{
public Age_Input Input { get; set; }
public Age_Processor(Age_Input input)
{
Input = input;
}
public override IDataPointOutput GetOutput()
{
Age_Output output = new Age_Output();
if (Input.AgeExact > 30)
{
output.DebugStrings.Add("Getting old");
}
else
{
output.DebugStrings.Add("Still young");
}
return output;
}
}
public class DecisionEngine
{
public void GetDecisions()
{
List<IDataPointInput> input = new List<IDataPointInput>();
input.Add(new Age_Input { AgeExact = 44 });
foreach (IDataPointInput item in input)
{
IDataPointProcessor processor = item.GetProcessor();
IDataPointOutput output = processor.GetOutput();
}
}
}
I'm developing a helper class to work with Lucene. It's meant to take an object into a factory and decorate the object with a method of indexing the object, adding an index strategy based on the type of object provided. The code looks something like this:
class IndexWrapper
{
public interface IDocumentable
{
Document BuildDocument();
}
public interface IDocumentBuilder
{
Type SupportedType { get; }
Document BuildDocument(object o);
}
public class StringDocumentBuilder : IDocumentBuilder
{
public Type SupportedType { get { return typeof(string); } }
public Document BuildDocument(object o)
{
Document doc = new Document();
doc.Add(new Field("string", o as string, Field.Store.YES, Field.Index.ANALYZED));
return doc;
}
}
public static class IndexableFactory
{
public static IDocumentable GetIndexableObject(object o)
{
return GetIndexableObject(o, DocumentBuilderFactory.GetBuilder(o));
}
public static IDocumentable GetIndexableObject(object o, IDocumentBuilder builder)
{
return new IndexableObject(o, builder);
}
}
public static class DocumentBuilderFactory
{
private static List<IDocumentBuilder> _builders = new List<IDocumentBuilder>();
public static IDocumentBuilder GetBuilder(object o)
{
if (_builders.Count == 0)
{
_builders = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(type => typeof(IDocumentBuilder).IsAssignableFrom(type) && type.IsClass)
.Select(type => Activator.CreateInstance(type))
.Cast<IDocumentBuilder>()
.ToList();
}
return _builders.Where(builder => builder.SupportedType.IsAssignableFrom(o.GetType())).FirstOrDefault();
}
}
private class IndexableObject : IDocumentable
{
object _o;
IDocumentBuilder _builder;
public IndexableObject(object o) : this(o, DocumentBuilderFactory.GetBuilder(o)) { }
public IndexableObject(object o, IDocumentBuilder builder)
{
_o = o;
_builder = builder;
}
virtual public Document BuildDocument()
{
return _builder.BuildDocument(_o);
}
}
}
What I'm wondering: Is it possible to include a default set of strategies for the class types users are most likely to see without including the libraries that contain those classes?