Skip to content

Commit

Permalink
Rough Draft finished
Browse files Browse the repository at this point in the history
  • Loading branch information
Leonard Sperry committed Jan 18, 2021
1 parent b893797 commit 568a7fb
Show file tree
Hide file tree
Showing 6 changed files with 361 additions and 16 deletions.
128 changes: 128 additions & 0 deletions SampleTests/Reflection/ExampleTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using Samples.Reflection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;

namespace SampleTests.Reflection
{

public class ExampleTests
{
static ExampleTests()
{
//initialize prior to test
//var type = typeof(CsvGeneratorFast.CsvBuilder<TestModel>);
//type.GetConstructors();
}
public ExampleTests()
{
}

[Fact]
public void TestSlow()
{
CsvGeneratorSlow generator = new CsvGeneratorSlow();

var results = generator.OutputToCsv(GetTestData(), '|').ToArray();
}
[Fact]
public void TestSlow2()
{
CsvGeneratorSlow generator = new CsvGeneratorSlow();

var results = generator.OutputToCsv(GetTestData(), '|').ToArray();
}

[Fact]
public void TestFast()
{
CsvGeneratorFast generator = new CsvGeneratorFast();

var results = generator.OutputToCsv(GetTestData(), '|').ToArray();
}

[Fact]
public void TestFast2()
{
CsvGeneratorFast generator = new CsvGeneratorFast();

var results = generator.OutputToCsv(GetTestData(), '|').ToArray();
}

//[Fact]
//public void TestWithException()
//{
// CsvGeneratorFast generator = new CsvGeneratorFast();

// var results = generator.OutputToCsv(new ExceptionModel[] { new ExceptionModel()}).ToArray();
//}

private IEnumerable<TestModel> GetTestData()
{
const int count = 5000000;
for (int i = 0; i < count; i++)
{
yield return new TestModel(i, "Enterprise\"D")
{
Captain = "James Kirk",
Class = "Constitution"
};
}
}
}

class TestModel
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime LaunchDate { get; set; }
public string Captain { get; set; }

//public string Captain2 { get; set; }
//public string Captain3 { get; set; }
//public string Captain4 { get; set; }
//public string Captain5 { get; set; }
//public string Captain6 { get; set; }
//public string Captain7 { get; set; }
//public string Captain8 { get; set; }
//public string Captain9 { get; set; }
//public string Captain0 { get; set; } = "Jean Luc Picard";
//public string Captain01 { get; set; } = "Jean Luc Picard";
//public string Captain02 { get; set; } = "Jean Luc Picard";
//public string Captain03 { get; set; } = "Jean Luc Picard";
//public string Captain04 { get; set; } = "Jean Luc Picard";
//public string Captain05 { get; set; } = "Jean Luc Picard";
//public string Captain06 { get; set; } = "Jean Luc Picard";
//public string Captain07 { get; set; } = "Jean Luc Picard";
//public string Captain08 { get; set; } = "Jean Luc Picard";
//public string Captain09 { get; set; } = "Jean Luc Picard";

public string Class { get; set; }

public TestModel(int id, string name)
{
ID = id;
Name = name;
}

public TestModel Custom { get { return new TestModel(1234,""); } }

public override string ToString()
{
return "Custom";
}
}

public class ExceptionModel
{
public int MyProperty
{
get
{
throw new Exception();
}
}
}
}
4 changes: 2 additions & 2 deletions Samples/OofOne/Examples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public IEnumerable<Book> GetRelatedBooks(Book book)
Dictionary<Book, int> bookCounts = new Dictionary<Book, int>();
foreach (var cat in _categoryProvider.GetCategories(book))
{
var categories = _bookProvider.GetBooksInCategory(cat.ID);
UpdateBookCounts(bookCounts, categories);
var booksInCat = _bookProvider.GetBooksInCategory(cat.ID);
UpdateBookCounts(bookCounts, booksInCat);
}

return bookCounts.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key);
Expand Down
162 changes: 162 additions & 0 deletions Samples/Reflection/CsvGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Samples.Reflection
{
public interface ICsvGenerator
{
IEnumerable<string> OutputToCsv<T>(IEnumerable<T> collection, char delimiter = ',');
}

public class CsvGeneratorSlow : ICsvGenerator
{
public IEnumerable<string> OutputToCsv<T>(
IEnumerable<T> collection, char delimiter = ',')
{
var properties = typeof(T).GetProperties(
BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead).ToArray();

yield return properties.Select(p => EscapeAndWrap(p.Name))
.Aggregate((p1, p2) => $"{p1}{delimiter}{p2}");

foreach (var item in collection)
{
yield return
properties.Select(p => EscapeAndWrap(GetValue(p, item)))
.Aggregate((p1, p2) => $"{p1}{delimiter}{p2}");
}
}

private string GetValue<T>(PropertyInfo prop, T obj)
{
try
{
var val = prop.GetValue(obj);
return val == null ? "null" : val.ToString();
}
catch (Exception)
{
return "error";
}
}

private static string EscapeAndWrap(string input)
{
return input;
return $"\"{input.Replace("\"", "\"\"")}\"";
}

}

public class CsvGeneratorFast : ICsvGenerator
{
static MethodInfo _toString;
static MethodInfo _aggregate;

static CsvGeneratorFast()
{
_toString = typeof(object).GetMethod("ToString");
_aggregate = typeof(Enumerable).GetMethods()
.First(m => m.Name == nameof(Enumerable.Aggregate) && m.GetGenericArguments().Length == 1).MakeGenericMethod(typeof(string));
}

public IEnumerable<string> OutputToCsv<T>(IEnumerable<T> objects, char delimiter = ',')
{
return CsvBuilder<T>.Actual(objects, delimiter);
}

private delegate string LineBuilder<T>(char delimiter, T item);
private delegate string HeaderBuilder(char delimiter);

private static class CsvBuilder<T>
{
static LineBuilder<T> _lineBuilder;
static HeaderBuilder _headerBuilder = null;

static CsvBuilder()
{
var properties = typeof(T).GetProperties(
BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead).ToArray();

if (!properties.Any())
{
return;
}

_headerBuilder = delimiter =>
properties.Select(p => EscapeAndWrap(p.Name))
.Aggregate((s1, s2) => $"{s1}{delimiter}{s2}");

var valueGetters =
properties.Select(prop => BuildPropertyGetter(prop)).ToArray();

_lineBuilder = (delimiter, item) =>
valueGetters.Select(getter =>
{
try
{
return getter(item);
}
catch (Exception)
{
return "error";
}
})
.Aggregate((s1, s2) => $"{s1}{delimiter}{s2}");
}

public static IEnumerable<string> Actual(IEnumerable<T> items, char delimiter)
{
yield return _headerBuilder(delimiter);
foreach (var item in items)
{
yield return _lineBuilder(delimiter, item);
}
}

private static Func<T, string> BuildPropertyGetter(PropertyInfo prop)
{
// we're going to build an expression
// if the property is a value type
// item => item.Property.ToString()
// otherwise
// item => item.Property == null ? "null" : item.Property.ToString();
var type = typeof(T);
var input = Expression.Parameter(typeof(T), "item");

var propExpression = Expression.Property(input, prop);

var toString = prop.PropertyType != typeof(string)
? (Expression)Expression.Call(propExpression, _toString)
: propExpression;


if (prop.PropertyType.IsValueType)
{
var lambda = Expression.Lambda<Func<T, string>>(toString, input).Compile();
return item => EscapeAndWrap(lambda(item));
}
else
{
var nullExpression = Expression.Constant(null);
var isNull = Expression.Equal(propExpression, nullExpression);
var condition = Expression.Condition(isNull, Expression.Constant("null"), toString);

var lambda = Expression.Lambda<Func<T, string>>(condition, input).Compile();
return item => EscapeAndWrap(lambda(item));
}
}

private static string EscapeAndWrap(string input)
{
return input;
return $"\"{input.Replace("\"", "\"\"")}\"";
}
}
}
}
57 changes: 57 additions & 0 deletions Samples/Reflection/Examples.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Samples.Reflection
{
public class Examples
{

void OkReflectionExamples<T>(MyType someObject)
{
// getting a referene to a Type
Type t = typeof(T);
t = someObject.GetType();

// getting member information
PropertyInfo propInfo = t.GetProperty(
nameof(MyType.MyProperty), BindingFlags.Public | BindingFlags.Instance);

MethodInfo methodInfo = t.GetMethod(
nameof(MyType.MyMethod), BindingFlags.DeclaredOnly);

//dicovering attributes
var attribute = t.GetCustomAttribute<MyAttribute>();

//discovering if a type is derived from or implements another
bool inherits = typeof(object).IsAssignableFrom(t);
}

void ExpensiveReflectionExamples(
object someObject,
PropertyInfo someProperty,
MethodInfo someMethod)
{
someProperty.GetValue(someObject);
someMethod.Invoke(someObject, null);
}

public class MyAttribute : Attribute
{

}

public class MyType : MyInterface
{
public int MyProperty { get; set; }
public void MyMethod() { }
}

public interface MyInterface
{
public int MyProperty { get; set; }
}
}
}
5 changes: 2 additions & 3 deletions Samples/SOLID/DIP/BusinessServiceWithDependencyInversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ public class BusinessServiceWithDependencyInversion
readonly ILogger _logger;

public BusinessServiceWithDependencyInversion(
IObjectProvider objProvider,
ILogger logger)
IObjectProvider objProvider, ILogger logger)
{
_objectProvider = objProvider;
_logger = logger;
}

public IEnumerable<SomeBusinessObject>
GetObjectsForSpecialUseCase(int categoryId)
GetObjectsForSpecialUseCase(int categoryId)
{
_logger.Log("beginning complex domain logic");
var objects = _objectProvider.GetObjectsByCategory(categoryId);
Expand Down
Loading

0 comments on commit 568a7fb

Please sign in to comment.