I'm creating an app that returns a list of metals to use in various conditions. I have a Metal class then classes for each type of Metal like Steel, Aluminum, etc. If I have a list of different Steels, I want to first select the best ones based on a set of properties common to all Metals then do a second pass based on the unique properties of Steel. (This isn't my exact problem but my problem is analogous.)
I can't figure out how to pass a List<Steel> to the GetBest() method of the Metal class as shown below that takes its first argument of type List<Metal>. The code won't compile due to error at the line highlighted below with **: "Argument 1: cannot convert from 'System.Collections.Generic.List<Steel>' to 'System.Collections.Generic.List<Metal>'.
public class Metal {
public int PropA { get; set; }
public List<Metal> GetBest( List<Metal> list, int condition1 )
{
var best = new List<Metal>();
//Analysis code here...
return best;
}
}
public class Steel : Metal
{
public int PropB { get; set; }
public List<Steel> GetBest(List<Steel> list, int condition1, int condition2 ) {
var bestSteel = new List<Steel>();
//Do first pass selection based on properties of all metals.
**bestSteel = Metal.GetBest(list, condition1);**
//Do some additional analysis based to Steel's unique properties.
//Analysis code here...
return bestSteel;
}
You could use a constrained generic method:
public static List<T> GetBest<T>(List<T> list, int condition1) where T : Metal
{
var best = new List<T>();
// Analysis code here...
return best;
}
I'm going to answer a different question! A look at how I might approach this problem without confounding my objects (Metal, Steel) with my logic for picking the best metal based on some conditions:
public class Metal{}
public class Steel:Metal{}
public class MetalPickerContext
{
public int Condition1{ get;set;}
}
public class MetalPicker<TMetal, TContext>
where TMetal: Metal
where TContext: MetalPickerContext
{
public virtual IEnumerable<TMetal> GetBest(IEnumerable<TMetal> list, TContext context)
{
var result = new List<TMetal>();
// logic for picking the best metal based on Condition1
return result;
}
}
public class SteelPickerContext: MetalPickerContext
{
public int Condition2{get;set;}
}
public class SteelPicker : MetalPicker<Steel,SteelPickerContext>
{
public override IEnumerable<Steel> GetBest(IEnumerable<Steel> list, SteelPickerContext context)
{
var initialResult = base.GetBest(list,context);
// Having called the base logic apply more with reference to Condition2
return initialResult;
}
}
This compiles (as you can see here) and I could expand the example a bit given some more details to make it a working one. Let me know if that would help you.
Related
I am looking at some legacy code and have come across an abstraction that has properties for each of its derived/concrete types. I cannot share the exact code but please imagine that instead of it being a simple operation that there are numerous operations that are much more complex.
I have not come across anything like this before and have a lot of questions? First, is this a pattern that I am not aware of? If so, what is it? Second question, how should I refactor this so that it follows solid principles?
I will try my best to come up with a better example if needed.
public enum ToolType
{
Unknown = 0,
HRMonitor,
Dumbell,
SomeForceDevice
}
public abstract class ToolData
{
private ToolData()
{
IsValid = false;
this.ToolType = ToolType.Unknown;
}
public ToolData(ToolType toolType)
{
this.ToolType = toolType;
}
public ToolType ToolType { get; }
public virtual bool IsValid { get; protected set; } = true;
public double LinkQuality { get; set; }
public NullToolDataValue NullData => this as NullToolDataValue;
public DumbellDataValue DumbellData => this as DumbellDataValue;
public HeartRateDataValue HRData => this as HeartRateDataValue;
public SomeForceDataValue SomeForceData => this as SomeForceDataValue;
}
public class NullToolDataValue : ToolData
{
public NullToolDataValue() : base(ToolType.Unknown)
{
IsValid = false;
}
}
public class DumbellDataValue : ToolData
{
public double WeightValue { get; private set; }
public DumbellDataValue(double weightValue) : base(ToolType.Dumbell)
{
this.WeightValue = weightValue;
}
public override string ToString()
{
return WeightValue.ToString(CultureInfo.InvariantCulture);
}
}
public class HeartRateDataValue : ToolData
{
public int HeartRate { get; private set; }
public HeartRateDataValue(int heartRate) : base(ToolType.HRMonitor)
{
this.HeartRate = heartRate;
}
public override string ToString()
{
return HeartRate.ToString(CultureInfo.InvariantCulture);
}
}
public class SomeForceDataValue : ToolData
{
public double LeftHandForceValue { get; private set; }
public double RightHandForceValue { get; private set; }
public int LeftHandPosition { get; private set; }
public int RightHandPosition { get; private set; }
public SomeForceDataValue(double lefthandValue, double rightHandValue, int leftHandPosition, int rightHandPosition) : base(ToolType.SomeForceDevice)
{
this.LeftHandForceValue = lefthandValue;
this.LeftHandPosition = leftHandPosition;
this.RightHandForceValue = rightHandValue;
this.RightHandPosition = rightHandPosition;
}
public override string ToString()
{
return $"{LeftHandForceValue.ToString(CultureInfo.InvariantCulture)}" +
$"| {LeftHandPosition.ToString(CultureInfo.InvariantCulture)}" +
$"| {RightHandForceValue.ToString(CultureInfo.InvariantCulture)}" +
$"| {RightHandPosition.ToString(CultureInfo.InvariantCulture)}";
}
}
It is being used/consumed via something like the below which it too is missing some inheritance and things for brevity:
public class DumbellExcercise
{
public void ToolDataReceived(ToolData data)
{
if (data?.DumbellData == null) return;
//add value to some collection
Collection.Add(data.DumbellData.WeightValue);
}
}
public class HRExcercise
{
public void ToolDataReceived(ToolData data)
{
if (data?.HRData == null) return;
//add value to some collection
Collection.Add(data.HRData.HeartRate);
}
}
Okay, I'm going to give a shot at answering - hopefully this will help.
First up, ToolData shouldn't contain any References/Enums/whatever that list its subtypes. So first on the chopping block: all the lambda properties that cast the object as a specific subtype. I can kinda understand the appeal - you know an instance of ToolType happens to be a FloobieTool, so you call instance.FloobieTool and magically get a FloobieTool cast. But... well, there are problems that come with it, not the least is that you're breaking Opened/Closed Principle. Nothing wrong with making the person calling the class cast it explicitly with (FloobieTool)instance if they know they're working with a FloobieTool.
Next up: the ToolType. Why do you need this? You can tell if your instance of ToolData is a FloobieTool by simply doing an 'is' check in an IF condition:
void SomeFunc(ToolData toolData)
{
if (!(toolData is FloobieTool)) throw new Exception("Non-Floobie!");
// more code
}
I mean, what does that enumeration actually get you? Because it has a definite cost: it has to be kept in-sync with the list of classes that implement ToolData.
Also, the part in ToolDataReceived() for each of those Exercise classes seems... weird. I mean, you've got an exercise, and you're passing in ToolData. Why are you storing the amount of the Dumbell exercise? As opposed to just storing the ToolData. I mean, you're going through quite a bit of testing/casting/etc, just to add the dumbbell weight to a Collection. Any reason you can't just store the ToolData instance and call it a day? If you really need to specifically store Dumbbell info, you could do something like:
public class DumbbellExercise
{
List<DumbbellDataValue> dumbbellData = new List<DumbbellDataValue>();
public void AddToolData(ToolData toolData)
{
if (toolData is DumbbellDataValue)
this.dumbbellData.Add((DumbbellDataValue)toolData);
}
}
Hopefully that helps - it's tough to go into too many details when we're working off an abstracted example of your actual problem :-)
Having seen your edits, I believe even more firmly that the way to refactor this code is to use pattern matching. Pattern matching requires at least C# 7.0 so I'll include an almost-as-good way to do it pre-7.0 versions.
Step 1
Mark the properties obsolete using ObsoleteAttribute and pass true for the error parameter.
[Obsolete("Use pattern matching instead.", true)]
public NullToolDataValue NullData => this as NullToolDataValue;
[Obsolete("Use pattern matching instead.", true)]
public DumbellDataValue DumbellData => this as DumbellDataValue;
[Obsolete("Use pattern matching instead.", true)]
public HeartRateDataValue HRData => this as HeartRateDataValue;
[Obsolete("Use pattern matching instead.", true)]
public SomeForceDataValue SomeForceData => this as SomeForceDataValue;
This will make it a compiler error to use them in any code processed by the compiler. If you're doing any reflection on them, you'll get a runtime exception instead (after step 3 is complete) if you don't also change that code.
Step 2
Modify every call site that uses those properties to use pattern matching instead. If all you're doing is what you showed in the question, is should be as simple as this:
public class DumbellExcercise
{
public void ToolDataReceived(ToolData data)
{
if (data is DumbellDataValue dumbell)
Collection.Add(dumbell.WeightValue);
// OR
if (!(data is DumbellDataValue dumbell))
return;
Collection.Add(dumbell.WeightValue);
}
}
The second variation is not as pretty because the condition has to be parenthesized before it can be negated (hey, at least VB has the IsNot keyword; go figure) but you get the same early return that the existing code has.
It looks like you're using at least C# 6.0 because you're using the null-coalescing operator (?.), but if you're not using at least 7.0, you can do this, instead:
public class DumbellExcercise
{
public void ToolDataReceived(ToolData data)
{
DumbellDataValue dumbell = data as DumbellDataValue;
if (dumbell != null)
Collection.Add(dumbell.WeightValue);
// OR
DumbellDataValue dumbell = data as DumbellDataValue;
if (dumbell == null)
return;
Collection.Add(dumbell.WeightValue);
}
}
Step 3
Remove the properties. If there are no more compiler errors, the properties aren't being used, so you're free to get rid of them.
Additional Note
The IsValid property has a strange duality to it. It can be assigned by the derived classes but it's also virtual so it can be overridden, too. You really should pick one. If it were my decision, I'd keep it virtual and make it read-only.
public abstract class ToolData
{
// Continue to assume it's true...
public virtual bool IsValid => true;
}
public class NullToolDataValue : ToolData
{
// ...and indicate otherwise as needed.
public override bool IsValid => false;
}
I would like to request what's the best way to handle the situation below.
I would like to call populate function for different instance with different parameters. I implemented populate function in each inheritance classes. But I don't know what's the best way to use it for hundreds of times.
(Eg index would be the total number of country in the world).
public enum TCountry
{
tAustralia,
tUnitedKingdom,
.. etc..
}
public enum TCity
{
tSydney,
tLondon,
... etc..
}
public int ProcessData ( string population, int index)
{
switch (index)
{
case 0:
TypeAust aus = new TypeAust();
retun aus.poulate( population, tAustralia, tSydney);
// Different calculation Sydney -Aus
DisplayAus(); // Display for Sydney - Aus
case 1:
TypeUK uk = new TypeUK();
retun uk.poulate( population, tUnitedKingdom, tLondon);
// Different calculation for Londond - UK
DisplayUK(); // Display for London - UK
....
... etc..
}
}
Thanks in Advance
I would recommend going with a different design. Rather than working with that case statement, put all your types in a collection and call populate without knowing what specific type you're working with.
List<TypeCountry> countries = new List<TypeCountry>() { new TypeUK(), TypeAus(), TypeUS() //ect };
//use this list all throughout the program
Instead of you switch statement you can just do;
return countries[index].populate( //args go here );
Then you can do other things like;
int worldPop = countries.Aggregate((c, n) => c.Populate(//args) + n.Populate(//args));
In general you need to stop treating each type as if it's different from the next. Move your logic into the base class, get rid of code that has to refer to the type by name or requires specific checks for which inheriting type it is. For almost all cases you should be able to have a collection of the base classes type and pass it around and work on it without ever knowing what type the specific instance you're dealing with is. If that's not the case then you're doing inheritance wrong. If you have that big case statement then there is no point in even using inheritance because as far as I can tell you're not getting any of it's benefits.
I would have to see more of your actual needs and architecture but you could look into generics.
public int ProcessData<T>(string population) where T : BaseCountry, new() {
var country = new T();
Display(country);
return country.Populate(population);
}
public void Display<T>(T country) where T : BaseCountry { ... }
You would use ProcessData like:
ProcessData<TypeAust>(99);
Your display method would be generic too. This way, your process data method is always constrained to work with anything that implements BaseCountry. BaseCountry would define an abstract or virtual Populate() method.
You could do something like this so the logic is broken out into different classes:
public enum TCountry
{
tAustralia,
tUnitedKingdom
}
public enum TCity
{
tSydney,
tLondon
}
public abstract class TypeCountry
{
public abstract int Populate(string population);
}
public class TypeAust : TypeCountry
{
public override int Populate(string population)
{
// do your calculation with tAustralia, tSydney...
}
}
public class TypeUK: TypeCountry
{
public override int Populate(string population)
{
// do your calculation with tUnitedKingdom, tLondon...
}
}
public static class TypeCountryFactory
{
public static TypeCountry GetCountry(TCountry country)
{
switch (country)
{
case TCountry.tAustralia:
return new TypeAust();
case TCountry.tUnitedKingdom:
return new TypeUK();
}
}
}
public int ProcessData (string population, int TCountry)
{
TypeCountry country = TypeCountryFactory.GetCountry(TCountry);
return country.Populate(population);
}
I'm creating a child object from a parent object. So the scenario is that I have an object and a child object which adds a distance property for scenarios where I want to search. I've chosen to use inheritance as my UI works equivalently with either a search object or a list of objects not the result of a location search. So in this case inheritance seems a sensible choice.
As present I need to generate a new object MyObjectSearch from an instance of MyObject. At present I'm doing this in the constructor manually by setting properties one by one. I could use reflection but this would be slow. Is there a better way of achieving this kind of object enhancement?
Hopefully my code below illustrates the scenario.
public class MyObject {
// Some properties and a location.
}
public class MyObjectSearch : MyObject {
public double Distance { get; set; }
public MyObjectSearch(MyObject obj) {
base.Prop1 = obj.Prop1;
base.Prop2 = obj.Prop2;
}
}
And my search function:
public List<MyObjectSearch> DoSearch(Location loc) {
var myObjectSearchList = new List<MyObjectSearch>();
foreach (var object in myObjectList) {
var distance = getDistance();
var myObjectSearch = new MyObjectSearch(object);
myObjectSearch.Distance = distance;
myObjectSearchList.add(myObjectSearch);
}
return myObjectSearchList;
}
The base class needs to define a copy constructor:
public class MyObject
{
protected MyObject(MyObject other)
{
this.Prop1=other.Prop1;
this.Prop2=other.Prop2;
}
public object Prop1 { get; set; }
public object Prop2 { get; set; }
}
public class MyObjectSearch : MyObject
{
public double Distance { get; set; }
public MyObjectSearch(MyObject obj)
: base(obj)
{
this.Distance=0;
}
public MyObjectSearch(MyObjectSearch other)
: base(other)
{
this.Distance=other.Distance;
}
}
This way the setting of properties is handled for all derived classes by the base class.
You can use reflection to copy properties.
public class ChildClass : ParentClass
{
public ChildClass(ParentClass ch)
{
foreach (var prop in ch.GetType().GetProperties())
{
this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(ch, null), null);
}
}
}
There is no easy way to do this, unfortunately. As you said, you would either have to use reflection, or create a "Clone" method that would generate a new child object using a parent object as input, like so:
public class MyObjectSearch : MyObject {
// Other code
public static MyObjectSearch CloneFromMyObject(MyObject obj)
{
var newObj = new MyObjectSearch();
// Copy properties here
obj.Prop1 = newObj.Prop1;
return newObj;
}
}
No matter what, you're either going to end up writing reflection code (which is slow), or writing each property out by hand. It all depends on whether or not you want maintainability (reflection) or speed (manual property copy).
A generic solution would be to serialize it to json and back. In the json-string is no information about the class name from which it was serialized.
Most people do this in javascript.
As you see it works well for pocco objects but i don't guarantee that it works in every complex case. But it does event for not-inherited classes when the properties are matched.
using Newtonsoft.Json;
namespace CastParentToChild
{
public class Program
{
public static void Main(string[] args)
{
var p = new parent();
p.a=111;
var s = JsonConvert.SerializeObject(p);
var c1 = JsonConvert.DeserializeObject<child1>(s);
var c2 = JsonConvert.DeserializeObject<child2>(s);
var foreigner = JsonConvert.DeserializeObject<NoFamily>(s);
bool allWorks = p.a == c1.a && p.a == c2.a && p.a == foreigner.a;
//Your code goes here
Console.WriteLine("Is convertable: "+allWorks + c2.b);
}
}
public class parent{
public int a;
}
public class child1 : parent{
public int b=12345;
}
public class child2 : child1{
}
public class NoFamily{
public int a;
public int b = 99999;
}
// Is not Deserializeable because
// Error 'NoFamily2' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type 'NoFamily2' could be found (are you missing a using directive or an assembly reference?)
public class NoFamily2{
public int b;
}
}
If a shallow copy is enough, you can use the MemberwiseClone method.
Example:
MyObject shallowClone = (MyObject)original.MemberwiseClone();
If you need a deep copy, you can serialize/deserialize like this: https://stackoverflow.com/a/78612/1105687
An example (assuming you write an extension method as suggested in that answer, and you call it DeepClone)
MyObject deepClone = original.DeepClone();
I first came accros this question when I was looking for doing this.
If you are able to work with C# 9 and record-classes. You only have to create a new constructor in the sub-class taking in a base class object and hand it over to the subclass:
public record MyObject {
...
}
public record MyObjectSearch :MyObject
{
public MyObjectSearch(MyObject parent) : base(parent) { }
...
}
Then you can create the child object like this:
MyObject parent = new();
MyObjectSearch m = new MyObjectSearch(parentObj) { Distance = 1.1};
Credits to https://stackoverflow.com/a/64573044/2582968
Seems natural for the base object to have constructor with parameters for its properties:
public class MyObject
{
public MyObject(prop1, prop2, ...)
{
this.Prop1 = prop1;
this.Prop2 = prop2;
}
}
So then, in your descendant object you can have:
public MyObjectSearch(MyObject obj)
:base(obj.Prop1, obj.Prop2)
This reduces duplication related to assignments. You could use reflection to automatically copy all properties, but this way seems more readable.
Note also, that if your classes have so much properties that you're thinking about automatizing of copying of the properties, then they are likely to violate the Single Responsibility Principle, and you should rather consider changing your design.
There are libraries to handle this; but if you just want a quick implementation in a few places, I would definitely go for a "copy constructor" as previously suggested.
One interesting point not mentioned is that if an object is a subclass, then it can access the child's private variables from the within the parent!
So, on the parent add a CloneIntoChild method. In my example:
Order is the parent class
OrderSnapshot is the child class
_bestPrice is a non-readonly private member on Order. But Order can set it for OrderSnapshot.
Example:
public OrderSnapshot CloneIntoChild()
{
OrderSnapshot sn = new OrderSnapshot()
{
_bestPrice = this._bestPrice,
_closed = this._closed,
_opened = this._opened,
_state = this._state
};
return sn;
}
NOTE: Readonly member variables MUST be set in the constructor, so you will have to use the child constructor to set these...
Although I don't like "up-sizing" generally, I use this approach a lot for analytic snapshots...
I've got a question about getting the values from a constructor in a generic way.
namespace myTestNamespace
{
Public Class myTestClass()
{
Public myTestClass(int myInt,bool myBool, double myDouble)
{
//do / set something
}
Public myTestClass(int myInt,bool myBool)
{
//do / set something
}
}
}
Using (what you need);
Using myTestNamespace;
namespace MyIWannaLookForTheParametersName
{
Public Class MyLookUpClass()
{
Public void DoSomething()
{
List<object> myList = new List<object>();
myTestClass _ myTestClass = new myTestClass(1,true,2.5);
object mySaveObject = myTestClass;
mylist.Add(mySaveObject);
//how do I get the info from the right constructor
//(I used the one with 3 parameters_
//what was the value of myInt, myBool and myDouble
//how can I make it generic enough, so it will work with other classes with
// different constructors ass well?
}
}
}
Questions about intent aside, there's no generic way for you to do this. Information about what methods have been called and what values were supplied is not saved automatically. You are, of course, perfectly able to keep track of these things yourself, but you would have to write each class to do this explicitly.
Doing this in a generic way is asking for trouble. What if I did this?
public class Foo
{
public string Name { get; set; }
}
public class Bar
{
public Bar(Foo foo)
{
// ...
}
}
Then suppose I called it in this way:
Foo f = new Foo();
f.Name = "Jim";
Bar b = new Bar(f);
f.Name = "Bob";
Now, if such a generic system existed, what would be the value of foo for the Bar constructor? Either it reports "Bob" (which is what the value for Name is on the instance of Foo that was supplied), or it reports "Jim", meaning that the runtime or library would essentially have to be smart enough to make a deep copy of the object so that the state is not changed.
The bottom line is this: if you need access to the parameters passed to the constructor (or any other function), you'll have to store them somewhere explicitly.
You can't get thevalues from the constructor. You need to first place them in a property or a field within your class. The example you provided is a poor use of generics. You wouldbe better off placing the constructor values into properties and creating an interface with those properties.
I got what I needed with this method:
private static ParameterSettings[] GetListOfParametersFromIndicator(object indicatorClass, int loopId, myEnums.ParaOrResult paraOrResult)
{
return (from prop in indicatorClass.GetType().GetProperties()
let loopID = loopId
let Indicator = indicatorClass.GetType().Name
let value = (object)prop.GetValue(indicatorClass, null)
where prop.Name.Contains("_Constr_")
select new ParameterSettings { ParaOrResult=paraOrResult, LoopID= loopId, Indicator= Indicator, ParaName= prop.Name, Value= value }).ToArray();
}
where ParameterSettings is:
public struct ParameterSettings
{
public myEnums.ParaOrResult ParaOrResult { get; set; }
public int LoopID { get; set; }
public string Indicator { get; set; }
public string ParaName { get; set; }
public object Value { get; set; }
}
This info is ok for me. Thanks for the replies.
Regards,
Matthijs
I want to be able to create "Transformation" classes that take a given object, perform a series of transformations on it (i.e. change property values) and keeps track of the transformations performed. The transformation performed will vary based on the properties of the object provided.
I want to be able to apply transformation rules (which are finite and commin) within a given transformation class using a fluent style interface.
At a high level, I understand that I will likely have an ITransformer, an ITransformationRule, and ITransformationResult, and a few other objects to make this happen.
How I would want the code to work when creating Transformation classes...
public OfflinePersonToOnlineTransformation : TransformerBase<Person>
{
public OfflinePersonToOnlineTransformation()
{
Transform(x => x.PersonClassification)
.WhenCreatedBefore("1/1/2000")
.ClassifyAs("Online");
}
}
I understand that my TransformerBase would need to implement the "Transform" method that takes a Func or Expression, and I understand that it would need to keep a collection of ITransformationRules. I also understand that I would likely use Extension methods for the "WhenCreatedBefore" and "ClassifyAs" methods.
The trouble is, I can't figure out how to make it all work. I've looked at source code for Fluent Validation .NET as it does validation this way, but the complexity is killing me. I'm looking for a tutorial that covers this, or someone to spell it out in a way that is a pretty straightforward.
Thanks in advance.
Not quite sure why you want to go to all this effort when linq does most of it for you:
IEnumerable<Person> somePeople; // from wherever
somePeople.Where(x => x.CreateDate < new DateTime(2000,1,1))
.ForEach(x => x.PersonClassification = "Online");
Simply by adding the ForEach from here noting the proisos for why it's not included by default.
If you want to make the WhereCreatedBefore nicer then a simple extension like so:
static class PersonExtensions
{
public static bool WhereCreatedBefore(this Person p,
int year, int month, int day)
{
return p.CreateDate < new DateTime(year,month,day);
}
}
which is useful in and of itself and gives you:
somePeople.Where(x => x.CreatedBefore(2000,1,1))
.ForEach(x => x.PersonClassification = "Online");
Why limit yourself when simply expanding on the tools linq gives you makes things easier.
If you want to chain multiple side effects a simple alteration of ForEach like so:
public static IEnumerable<T> Modify<T>(
this IEnumerable<T> input, Action<T> action)
{
foreach (var x in input)
{
action(x);
yield return x;
}
}
giving you:
somePeople.Where(x => x.CreatedBefore(2000,1,1))
.Modify(x => x.PersonClassification = "Online");
.Modify(x => x.LastModifiedBy = Environment.UserName);
Or if you use the language integrated part of it:
(from p in somePeople where p.CreatedBefore(2000,1,1)) select p)
.Modify(p => p.PersonClassification = "Online");
.Modify(p => p.LastModifiedBy = Environment.UserName);
IF you really* wanted to you could write a ClassifyAs extension like so:
public static IEnumerable<Person> ClassifyAs(
this IEnumerable<Person> input, string classification)
{
foreach (var p in input)
{
p. PersonClassification = classification;
yield return p;
}
}
giving you your original of:
(from p in input where p.CreatedBefore(2000,1,1)) select p).ClassifyAs("Online");
Which is a one liner! with no fancy frameworks or type hierarchies required, just some useful extension methods.
Linq is generally well designed, well implemented, ubiquitous and well integrated into c#. Reimplementing the query parts of it would be foolish and wasteful, what you want is to add side effect causing operations to it. This is fine (you have mutable objects so this is hardly causing a problem) just add those operations. Just making them continue to yield their input will make your code fluent in style.
I had a think; Its only pseudo code but does this help?
public interface IPerson {
string PersonClassification { get; set; }
DateTime CreateDate { get; set; }
}
public class Person : IPerson {
public string PersonClassification { get; set; }
public DateTime CreateDate { get; set; }
}
public class TransformerBase<T>
where T : IPerson {
T Person { get; set; }
T Transform(Func<T, PersonClassification> transformer) {
return transformer(person);
}
}
public class OfflinePersonToOnlineTransformation : TransformerBase<Person>
{
public OfflinePersonToOnlineTransformation()
{
Transform(x => x.PersonClassification)
.WhenCreatedBefore("1/1/2000")
.ClassifyAs("Online");
}
}
public static class Extensions {
public static T WhenCreatedBefore<T>(this T person, string date) where T : IPerson{
if(person == null || person.CreateDate > DateTime.Parse(date))
return null
return person;
}
public static T Classify<T>(this T person, string classification)where T : IPerson{
if(person != null)
person.PersonClassification = classification;
return person;
}
}
It might help to take a step back and write a simple fluent interface first. You don't need generics or multiple classes to implement one. The main benefit of the fluent interface pattern is easy to read code. It's accomplished by returning this from methods to promote method chaining. Here's a basic example. I would start here and work backward to your desired result.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
class Calculator
{
List<int> values = new List<int>();
public Calculator Add(int value)
{
values.Add(value);
return this;
}
public int Count()
{
return values.Count;
}
public int Sum()
{
return values.Sum();
}
}
private void Form1_Load(object sender, EventArgs e)
{
//returns 3
int sum =
new Calculator()
.Add(1)
.Add(2)
.Sum();
}
}