Alternative To A Series Of Overloaded Methods - c#

I have a helper class that does a simple but repetitive process on a List of entities. For simplicity, it's like this...
public static List<MyType> DoSomethingSimple(List<MyType> myTypes) {
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
I now need to add support for another type, but everything is identical... how do I avoid an increasing list of overloaded methods like this:
public static List<MyType> DoSomethingSimple(List<MyType> myTypes) {
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
public static List<MyOtherType> DoSomethingSimple(List<MyOtherType> myOtherTypes) {
return myOtherTypes.Where(myOtherType => myOtherType.SomeProperty.Equals(2)).ToList();
}
... and so on.

Here's two ways:
Use generics, and a common base class
Use interfaces
Method 1:
public class BaseClass
{
public int SomeProperty { get; set; }
}
public class MyType : BaseClass { }
public class MyOtherType : BaseClass { }
public class ClassWithMethod
{
public static List<T> DoSomethingSimple<T>(List<T> myTypes)
where T : BaseClass
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Method 2:
public interface ICommon
{
int SomeProperty { get; set; }
}
public class MyType : ICommon
{
public int SomeProperty { get; set; }
}
public class MyOtherType : ICommon
{
public int SomeProperty { get; set; }
}
public class ClassWithMethod
{
public static List<T> DoSomethingSimple<T>(List<T> myTypes)
where T : ICommon
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Now, if you try to make the method use the interface directly, like this:
public class ClassWithMethod
{
public static List<ICommon> DoSomethingSimple(List<ICommon> myTypes)
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Then that would work if you have a List<ICommon> when you call it, but won't work if you have a List<MyType>. In C# 4.0 this can be done if we change the method slightly:
public class ClassWithMethod
{
public static List<ICommon> DoSomethingSimple(IEnumerable<ICommon> myTypes)
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Note that I changed to using an IEnumerable<ICommon> instead. The concept here is called Co- and contra-variance, and beyond that I'm not going to say much about it. Search Stack Overflow for more information on the subject.
Tip: I would change the input parameter to be IEnumerable<T> regardless, since this would make your method usable in more instances, you could have different types of collections, arrays, etc. and as long as they contain the right type, they can be passed to the method. By limiting yourself to List<T> you force the user of your code to convert to a list in some cases. My guidelines are to be as unspecific as possible in input parameters, and as specific as possible in output parameters.

Assuming the property has the same name and type for each list type, you could add an interface containing the property and implement it for each type you want to call this method on:
public interface ISomeProperty
{
object SomeProperty { get; }
}
DoSomethingSimple could then be:
public static List<T> DoSomethingSimple<T>(IEnumerable<T> list) where T : ISomeProperty
{
return list.Where(i => i.SomeProperty.Equals(2)).ToList();
}

Related

Infer type argument from containing class

I am trying to create something very similar to how EF Core uses builders in their entity configuration (e.g., IEntityTypeConfiguration<TEntity>, EntityTypeBuilder<TEntity>, PropertyBuilder<TEntity>).
In the below code, I would like the ObjectBuilder<> class and SubObject() method to infer the type from the class they are implemented in (in this case, MyClass). Is this possible?
It would also be great if I could infer the second type from the interface being implemented (the SomeType type), but I am pretty sure this is not possible.
It may be that I need a completely different approach to this, but I have yet to come up with an alternate solution.
Thank you for the help.
public interface ISomeInterface<T2> { }
public class SomeType
{
public string MySubObjectField { get; }
public string MySubObjectField2 { get; }
}
public class MyClass : ISomeInterface<SomeType>
{
public string MyObjectField { get; }
public string MyObjectField2 { get; }
public MyClass()
{
ObjectBuilder<MyClass, SomeType> builder = new ObjectBuilder<MyClass, SomeType>();
builder
.SubObject<MyClass>(c => c.MyObjectField)
.HasSomething(t => t.MySubObjectField)
.IsSomething();
builder
.SubObject<MyClass>(c => c.MyObjectField2)
.HasSomething(t => t.MySubObjectField2);
}
}
public class ObjectBuilder<T1, T2>
{
public SubObjectBuilder<T2> SubObject<T1>(Expression<Func<T1, object>> expression)
{
// Simplified for question
return new SubObjectBuilder<T2>();
}
}
public class SubObjectBuilder<T2>
{
public SubObjectBuilder<T2> HasSomething(Expression<Func<T2, object>> expression)
{
// Do something
return this;
}
public SubObjectBuilder<T2> IsSomething()
{
// Do something
return this;
}
}

"Reverse" type inference possible?

Given the following classes (factories used because C# doesn't support type inference on constructors):
public class A<T>
{
public A(B<T> b) { }
}
public class B<T>
{
public B(C<T> c) { }
}
public class C<T>
{
public C(T tee) { }
}
public class D<T>
{
public static D<T> Create<V>(Expression<Func<T, V>> property)
{
return new D<T, V>(property);
}
}
public class D<T, V> : D<T>
{
public D(Expression<Func<T, V>> property) { }
}
public class Model
{
public int P1 { get; set; }
public string P2 { get; set; }
}
public class AFactory
{
public static A<T> Create<T>(B<T> bee)
{
return new A<T>(bee);
}
}
public class BFactory
{
public static B<T> Create<T>(C<T> cee)
{
return new B<T>(cee);
}
}
public class CFactory
{
public static C<T> Create<T>(params D<T>[] tees)
{
return null;
}
}
The following compiles:
AFactory.Create(BFactory.Create(CFactory.Create(
D<Model>.Create(m => m.P1), D<Model>.Create(m => m.P2)
)));
The following does not:
AFactory.Create<Model>(BFactory.Create(CFactory.Create(
D.Create(m => m.P1), D.Create(m => m.P2)
)));
The difference is that in the first example I'm specifying the type of the model on the innermost classes, so type inference works normally and propagates up the tree. The problem is that I then have to specify the model type on every D.Create() call, which seems redundant.
The second example is the way I'd like to write this code: tell the outermost class that its type is Model and all the classes that are being constructed use that type as well. Essentially, it's syntactic sugar for AFactory.Create<Model>(BFactory.Create<Model>(/* turtles all the way down... */)).
Is there any way to achieve this in C#? I've tried all the permutations of inheritance and type constraints that I can think of, but nothing has given me the desired result.
I'm also fully aware that I might be missing something fundamental about generics - please feel free to educate me if that's the case.

Generic Type Parameter Inference

I've got a handy collection in my middle tier which is for collections of child things that belong to a parent thing.
public class ChildCollection<TParent, TChild>
{
public IEnumerable<TChild> GetChildren();
etc.
}
In the interface, I've got a handy grid that can display the contents of a ChildCollection<TParent,TChild> and let users do work on it.
public abstract class ChildCollectionGrid<TCollection, TParent, TChild> : MyGridControl
where TCollection : ChildCollection<TParent, TChild>
{
public abstract TCollection Collection;
etc.
}
Inheriting this class to make a grid to work with the Waffles on a Widget ends up looking like this.
public class WidgetWafflesGrid : ChildCollectionGrid<WidgetWafflesCollection, Widget, Waffle>
This is a little redundant. A WidgetWaffleCollection is a ChildCollection<Widget,Waffle>. With that first generic type argument specified, the class won't compile unless you specify exactly those two others.
Is there a prettier way to accomplish this where the compiler could infer those other two types? I know I'm being finicky but ideally I would like to have the class declaration look like:
public class WidgetWafflesGrid : ChildCollectionGrid<WidgetWafflesCollection>
Thanks for your help!
No, there's not. Generic parameter inference works only on methods.
Why derive from your collection? Just keep it like:
public abstract class ChildCollectionGrid<TParent, TChild> : MyGridControl
{
public abstract ChildCollection<TParent, TChild> Collection;
etc.
}
public class WidgetWafflesGrid : ChildCollectionGrid<Widget, Waffle>
{
}
The only way to handle inheritance in collections with Generics is using the Collection<TCollection,TChild> : where TCollection : Collection<TCollection,TChild> { } pattern.
Here is an example with a concrete class
public abstract class Collection<TCollection, TChild>
where TCollection : Collection<TCollection, TChild>, new()
{
protected Collection()
{
List=new List<TChild>();
}
protected List<TChild> List { get; set; }
public TCollection Where(Func<TChild, bool> predicate)
{
var result=new TCollection();
result.List.AddRange(List.Where(predicate));
return result;
}
public void Add(TChild item) { List.Add(item); }
public void AddRange(IEnumerable<TChild> collection) { List.AddRange(collection); }
}
public class Waffle
{
public double Temperature { get; set; }
}
public class WafflesCollection : Collection<WafflesCollection, Waffle>
{
public WafflesCollection BurnedWaffles
{
get
{
return Where((w) => w.Temperature>108);
}
}
}
class Program
{
static void Main(string[] args)
{
WafflesCollection waffles=new WafflesCollection();
// Count = 3
waffles.Add(new Waffle() { Temperature=100 });
waffles.Add(new Waffle() { Temperature=120 });
waffles.Add(new Waffle() { Temperature=105 });
var burned=waffles.BurnedWaffles;
// Count = 1
}
}

Creating a base class based in List<T>

I have a need to create a couple of classes that will serve as base classes for some data functionality I want to implement.
The first, we'll call SessionObjectDataItem looks like this ...
public class ObjectSessionDataItem
{
public int ID { get; set; }
public bool IsDirty { get; set; }
public bool IsNew { get; set; }
public bool IsRemoved { get; set; }
}
And next I want a List called ObjectSessionDataList and this is where I get stuck.
I can create the class OK ...
public class SessionObjectDataList<SessionObjectDataItem> : List<SessionObjectDataItem>
{
}
where I fall down is trying to define properties on the list that access items in it. For example, I want to write...
public List<SessionObjectDataItem> DirtyItems
{
get
{
return this.Where(d => d.IsDirty).ToList();
}
}
but VS refuses to recognise the SessionObjectDataItem property IsDirty inside the List object definition.
What I'm trying to end up with is a case where I might define
public class AssociatedDocument : SessionObjectDataItem
{
...
}
public class DocumentList : SessionObjectDataList
{
}
And then be able to say...
DocumentList list = new DocumentList();
...
foreach(AssociatedDocument doc in list.DirtyItems)
{
...
}
Can I actually do what it is that I'm attempting? Am I just doing it wrong?
Generic constraints will help here; you can write a container-class for which the generic type-parameter is constrained to be SessionObjectDataItem or one of its subtypes. This will allow you to construct a generic class that can hold instances of a specific sub-type of SessionObjectDataItem.
public class SessionObjectDataList<T> : List<T> where T : SessionObjectDataItem
{
public SessionObjectDataList<T> DirtyItems
{
get
{
return this.Where(d => d.IsDirty).ToList();
}
}
}
Usage:
var list = new SessionObjectDataList<AssociatedDocument>();
...
foreach(AssociatedDocument doc in list.DirtyItems)
{
...
}
Try to use the generic version Where<T> of the queryable interface:
public List<SessionObjectDataItem> DirtyItems
{
get
{
return this.AsQueryAble().Where<SessionObjectDataItem>(d => d.IsDirty).ToList();
}
}
Else Where simply assumes d as type Object.

C# Generics and Inheritance Problem

Hey, I'd like to know if what I'm trying to do is even possible? Comments in code should give and idea what I'm trying to achive :)
interface ITest<T> {
T t { get; }
bool DoTest();
}
public abstract class Test<T> : ITest<T> {
public Test (T nt) {
this.t = nt;
}
public Test () {
}
public T t {
get;
private set;
}
public abstract bool DoTest ();
}
public class STest : Test<string> {
public override bool DoTest () {
return true;
}
}
public class ITest : Test<int> {
public override bool DoTest () {
return true;
}
}
public class TestTest {
// I don't want to specify type here, I'd like TestTest to be able to have
// either a ITest or a STest. But for this class it should not matter.
// I just want to use DoTest() later on. No matter what
// specialication of Test this is.
Test myTest;
}
This might be a design problem, and I'd be willing to reconsider that if it is :)
I would suggest extracting the DoTest method to a super-interface, like this:
interface ITestable
{
bool DoTest();
}
interface ITest<T> : ITestable
{
T t { get; }
}
public class TestTest
{
ITestable myTest;
}
On an unrelated note, it is not recommended for class-names to begin with 'I' and for properties to begin with lower-case characters.
Place the DoTest() method in a non-generic ITest interface. Also, I would recommend making the ITest interface have a non-generic version of t. This is a quite common approach seen with interfaces like IEnumerable and IEnumerable<T>. The advantage is the non-generic version doesn't get less-capable and can hence can be fully leveraged in places where no actual type parameter can be supplied.
interface ITest
{
object t { get; }
bool DoTest();
}
interface ITest<T> : ITest
{
T t { get; }
}
Thanks to explicit implementation the unwanted non-generic or generic version (depending on the actual situation) can be hidden:
class STest : ITest<S>
{
public string t { get; private set; }
string ITest.t { get { return t; } }
public bool DoTest { ... }
}

Categories