Best way to use generics - c#

So I'm new to generics. But generics seem like a great way to reduce code. here is the scenario. I have a MVC Web API.
http://www.google.com/{controller}/{chartType}/{id}
NOTE: id is optional
I have several chart types which return similar objects:
HourlyDeviceChart
HourlyUsersCharrt
HourlyAvgProcessingTime
etc..
I would like to have just one method that evaluates the chart type parameter and executes the corresponding actions. instead of 8 or 10 methods.
I would be accepting if my design needs some refactoring. I'm open to suggestions. The idea here is to reduce some code. I would hate to have 10 methods exposed in the Web API and then 10 more corresponding methods in another class. Just seems redundant.
As always your suggestions are welcomed!
The method exposed by the API:
IEnumerable<T> GetChart(string chartType)
{
switch(chartType)
{
case "DeviceChart":
return repository.HourlyDeviceChart();
break;
case "UserChart":
return repository.HourlyUsersChart();
break;
}
}
//Then the class that handles all the work would look something like the below
IEnumerable<HourlyDeviceChart> HourlyDeviceChart()
{
// select appropriate items from the queue
// populate HourlyDeviceChart object
// add object to list
// return HourlyDeviceChart list
}
IEnumerable<UserDeviceChart> HourlyUsersChart()
{
// do more of the same
}

You can use generics like this:
interface IChart {
bool IsCharItemNeeded(IChartItem item);
void AddChartItem(IChartItem item);
}
IEnumerable<T> Charts<T>() where T : new, IChart {
var res = List<T>();
foreach (QueueCommand command in MyBigQueue) {
var chart = new T();
foreach (IChartItem item in command) {
if (chart.IsCharItemNeeded(item)) {
chart.AddChartItem(item);
}
}
res.Add(chart);
}
return res;
}
All chart types need to implement the common IChart interface. The where T : new, IChart line provides a constraint that lets you call new T(); for that, all chart classes must also implement a no-argument constructor.
Now you can use your generic code like this:
IEnumerable<UserChart> userCharts = Charts<UserChart>();
IEnumerable<DeviceChart> deviceCharts = Charts<DeviceChart>();

If both HourlyUserChart and HourlyDeviceChart methods work in same fashion, then dasblinkenlight's answer is good, you can have one generic way of populating them. If you need to populate them differently in two repository methods, may be something like these will do:
1)
interface IHourlyChart {
IEnumerable<IHourlyChart> Create();
}
class HourlyDeviceChart : IHourlyChart
{
public IEnumerable<IHourlyChart> Create()
{
return repository.HourlyDeviceChart();
}
}
class HourlyUsersChart : IHourlyChart
{
public IEnumerable<IHourlyChart> Create()
{
return repository.HourlyUsersChart();
}
}
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
return (IEnumerable<T>)new T().Create();
}
2) Or make it a tad more strongly typed via generics.
interface IHourlyChart<T> where T : IHourlyChart<T> {
IEnumerable<T> Create();
}
class HourlyDeviceChart : IHourlyChart<HourlyDeviceChart>
{
public IEnumerable<HourlyDeviceChart> Create()
{
return repository.HourlyDeviceChart();
}
}
class HourlyUsersChart : IHourlyChart<HourlyUsersChart>
{
public IEnumerable<HourlyUsersChart> Create()
{
return repository.HourlyUsersChart();
}
}
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
return new T().Create();
}
3) Or some reflection, which is still better than your type checking:
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
//find necessary method and invoke. may be:
return repository.GetType()
.GetMethods()
.Single(x => x.ReturnType == typeof(IEnumerable<T>))
.Invoke(repository, new object[0]) as IEnumerable<T>;
}
4) Worst case, do type checking inside your generic method, but check on the type itself, not any magic strings which is very brittle.
IEnumerable<T> GetChart<T>()
{
if (typeof(T) == typeof(HourlyDeviceChart))
return (IEnumerable<T>)repository.HourlyDeviceChart();
else if (typeof(T) == typeof(HourlyUsersChart))
return (IEnumerable<T>)repository.HourlyUsersChart();
// throw;
}
Call them all like:
var chartables = GetChart<HourlyUserChart>(); //etc

You should be able to do this by using a new interface and applying a constraint to your method GetChart
//Interface with a Type parameter to specify the return type of the method
public interface IChart<T>
{
IEnumerable<T> HourlyChart();
}
//How to implement the interface
public class HourlyDeviceChart : IChart<HourlyDeviceChart>
{
public static IEnumerable<HourlyDeviceChart> HourlyChart()
{
//Do work
}
}
//Your new method with a constraint applied
IEnumerable<T> GetChart<T>(string chartType) where T : IChart<T>
{
return T.HourlyChart();
}

Related

C# Return generic abstract class

I have the following type hierarchy:
public interface IDocument<TItem>
{
IEnumerable<TItem> Query(string query);
string FileName { get; }
}
public abstract class Document<TDocument, TItem> : IDocument<TItem>
{
public abstract IEnumerable<TItem> Query(string query);
public string FileName { get; private set; }
protected readonly TDocument _content;
}
public class DocumentX : Document<string, int>
{
...
}
public class DocumentY : Document<string, TypeOther>
{
...
}
and so on...
And I want to create a factory method, like this:
private IEnumerable<IDocument<T>> Factory<T>()
where T : IDocument<T>
{
yield return new DocumentX();
yield return new DocumentY();
}
The goal is to have a factory method, that will return a collection with different concrete implementations, which are derived from a common interface (IDocument)
But a compiler error raise:
"Cannot implicitly convert type 'DocumentX' to 'IDocument'. An explicit conversion exists (are you missing a cast?)"
What did I miss?
This is a misuse of generics. If your method is generic, it should not decide what T is. The caller decides what T is. Right now, your Factory method is making assumptions about what T exactly is. This shows that Factory should not be generic.
What you are trying to say, is something like
Hey, caller of Factory, I'm going to return a bunch of IDocument<T>s, but you don't know what the T of each one is going to be.
That's what happens when you put both a DocumentX and a DocumentY into an IEnumerable. Imagine that I'm consuming the IEnumerable returned by Factory. I won't know what kind of document each element I get is. i.e.
foreach (IDocument<???> document in Factory()) {
??? queryResult = document.Query("some query");
}
I will have no idea what I should put in ???.
Well actually, I do have a little idea of what Query would return. If I write:
foreach (IDocument<object> document in Factory()) {
object queryResult = document.Query("some query");
}
That would work, since everything can be converted to object. So we just need to write an AnyDocument class that conforms to IDocument<object>:
public class AnyDocument : IDocument<object> {
public string FileName { get; private set; }
private Func<string, IEnumerable<object>> query;
public IEnumerable<object> Query(string query)
{
return this.query(query);
}
private AnyDocument() { }
// this is used to convert an `IDocument<T>` to an AnyDocument
public static AnyDocument FromDocument<T>(IDocument<T> document) {
var doc = new AnyDocument();
doc.FileName = document.FileName;
doc.query = s => document.Query(s).Cast<object>();
return doc;
}
}
And now you can declare Factory like this:
private IEnumerable<IDocument<object>> Factory()
{
yield return AnyDocument.FromDocument(new DocumentX());
yield return AnyDocument.FromDocument(new DocumentY());
}
This whole thing could have been a lot simpler if the T in IDocument<T> is limited to reference types, i.e. no IDocument<int> like in DocumentX. Because then you can just use generic variance:
// just add the word "out"
public interface IDocument<out TItem>
Actually, I would say you should do this regardless, because then you can directly return the document objects if T is a reference type, and use AnyDocument only if T is a value type:
private IEnumerable<IDocument<object>> Factory()
{
yield return AnyDocument.FromDocument(new DocumentX());
yield return new DocumentY(); // let's say "OtherType" is a reference type
}
Try:
private IEnumerable<IDocument<T>> Factory<T>() where T : IDocument<T>, class
{
yield return new DocumentX() as T;
yield return new DocumentY() as T;
}
By casting the DocumentX, DocumentY as T you ensure all of them are at least of type IDcoument<T>, if not the class T which implements IDocument<T>.

C# Generic Interface and Factory Pattern

I am trying to create a Generic interface where the parameter type of one of the methods is defined by the generic
EDIT
I've changed the question slightly after realising I have probably confused matters by specifying a type parameter in the Factory creation method. What I have is two types of API calls that I need to make to a 3rd party API. The first retrieves a record from the API using an Id that is an int. The second also retrieves a record from the API but the Id is a string (guid). I have a class for each record type (ClientEntity and InvoiceEntity) that both implement a Generic Interface where I pass in the Id type
This is the Interface in which I declare a Method with an id Parameter
public interface IGeneric<TId>
{
void ProcessEntity(TId id);
}
I implement the interface in a couple of classes, one sets the id to be an int, the other a string.
public class ClientEntity: IGeneric<int> // Record with Id that is an int
{
public void ProcessEntity(int id)
{
Console.WriteLine(id);
// call 3rd party API with int Id
}
}
public class InvoiceEntity: IGeneric<string> // Record with Id that is a string (guid)
{
public void ProcessEntity(string id)
{
Console.WriteLine(id);
// call 3rd party API with string Id
}
}
What I would like to know is how do I use this within a factory pattern?
public static class GenericFactory
{
public static IGeneric<WhatGoesHere> CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (type == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
}
The objective is to use the factory to instantiate the correct class so that I can call the ProcessEntity method
EDIT
I don't want to have to pass in the Generic type to the factory method because the class that is created by the factory should handle that. When I create the object, I don't know what Id type is required, I want the factory to handle that
e.g.
var myGeneric = GenericFactory.CreateGeneric("Client");
myGeneric.ProcessEntity("guid")
or
var myGeneric = GenericFactory.CreateGeneric("Invoice");
myGeneric.ProcessEntity(1234)
I hope that makes sense
You should be able to do something like this:
public static class GenericFactory
{
public static IGeneric<T> CreateGeneric<T>()
{
if (typeof(T) == typeof(string))
{
return (IGeneric<T>) new GenericString();
}
if (typeof(T) == typeof(int))
{
return (IGeneric<T>) new GenericInt();
}
throw new InvalidOperationException();
}
}
You would use it like this:
var a = GenericFactory.CreateGeneric<string>();
var b = GenericFactory.CreateGeneric<int>();
Note that this uses a strongly-typed call rather than passing in the type name as a string (which may or may not be what you actually want).
If instead you want to pass a string for the type name, you will have to return an object because there is no way to return the actual type:
public static object CreateGeneric(string type)
{
switch (type)
{
case "string": return new GenericString();
case "int": return new GenericInt();
default: throw new InvalidOperationException("Invalid type specified.");
}
}
Obviously if you have an object you would normally have to cast it to the right type in order to use it (which requires that you know the actual type).
Alternatively, you could use reflection to determine what methods it contains, and call them that way. But then you'd still need to know the type in order to pass a parameter of the right type.
I think that what you are attempting to do here is not the right approach, which you will discover once you start trying to use it.
Hacky solution: Use dynamic
Nevertheless, there is one way you can get something close to what you want: Use dynamic as follows (assuming that you are using the object CreateGeneric(string type) factory method from above):
dynamic a = GenericFactory.CreateGeneric("string");
dynamic b = GenericFactory.CreateGeneric("int");
a.ProcessEntity("A string");
b.ProcessEntity(12345);
Be aware that dynamic uses reflection and code generation behind the scenes, which can make the initial calls relatively slow.
Also be aware that if you pass the wrong type to a method accessed via dynamic, you'll get a nasty runtime exception:
dynamic a = GenericFactory.CreateGeneric("string");
a.ProcessEntity(12345); // Wrong parameter type!
If you run that code, you get this kind of runtime exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 'ConsoleApplication1.GenericString.ProcessEntity(string)' has some invalid arguments
at CallSite.Target(Closure , CallSite , Object , Int32 )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at ConsoleApplication1.Program.Main() in D:\Test\CS6\ConsoleApplication1\Program.cs:line 71
Usually for that Factory using some DI container (DI can be useful, for example, when GenericInt or GenericString has dependencies), but to demonstrate just Idea how you can resolve this:
void Main()
{
GenericFactory.CreateGeneric<int>();
GenericFactory.CreateGeneric<string>();
}
public static class GenericFactory
{
private static Dictionary<Type, Type> registeredTypes = new Dictionary<System.Type, System.Type>();
static GenericFactory()
{
registeredTypes.Add(typeof(int), typeof(GenericInt));
registeredTypes.Add(typeof(string), typeof(GenericString));
}
public static IGeneric<T> CreateGeneric<T>()
{
var t = typeof(T);
if (registeredTypes.ContainsKey(t) == false) throw new NotSupportedException();
var typeToCreate = registeredTypes[t];
return Activator.CreateInstance(typeToCreate, true) as IGeneric<T>;
}
}
public interface IGeneric<TId>
{
TId Id { get; set; }
void ProcessEntity(TId id);
}
public class GenericInt : IGeneric<int>
{
public int Id { get; set; }
public void ProcessEntity(int id)
{
Console.WriteLine(id);
}
}
public class GenericString : IGeneric<string>
{
public string Id { get; set; }
public void ProcessEntity(string id)
{
Console.WriteLine(id);
}
}
The answer marked correct is fine if you want to use Static class but but what if you
want to return an DI injected type instead of newing an object? I suggest the
following!
public interface IGenericFactory
{
IGeneric<T> GetGeneric<T>() where T : class;
}
public class GenericFactory: IGenericFactory
{
private readonly IGeneric<int> intGeneric;
private readonly IGeneric<string> stringGeneric;
public GenericFactory(IGeneric<int> intG, IGeneric<string> stringG)
{
intGeneric = intG;
stringG = stringG;
}
public IGeneric<T> GetGeneric<T>() where T : class
{
if (typeof(T) == typeof(IGeneric<int>))
return (IGeneric<T>)Convert.ChangeType(intGeneric, typeof(IGeneric<T>));
if (typeof(T) == typeof(IGeneric<string>))
return (IGeneric<T>)Convert.ChangeType(stringGeneric,typeof(IGeneric<T>));
else
throw new NotSupportedException();
}
}
Please note i simply injected the two expected return types for clarity in the constructor. I could have implemented the factory as a Dictionary and injected the return objects into this Dictionary. Hope it helps.
I'm thinking you don't want to have to enter the type parameter similar to the LINQ methods. However the magic behind that happens because the type parameter is used in the normal parameter definitions. For example in the ToList<string>() method you can see that TSource is used between the parenthesis.
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);
That's how the compiler knows that you want a List<string> if you call ToList() instead of ToList<string>() when called from an IEnumerable<string>
However, I don't think you need a generic type parameter in your factory method at all. All you have to do is create a non-generic version of your TGeneric<TId>
public interface IGeneric { }
public interface IGeneric<TId> : IGeneric
{
void ProcessEntity(TId id);
}
And remove the <WhatGoesHere> from the CreateGeneric method:
public static IGeneric CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (recordType == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
If the function does not know the type, make it generic.
If the children are generics of different types (<int>, <string>), return object and cast inside the same factory class (Factory<T>), It is safe by typeof.
Personally, I prefer to specify the type with generics, without using an additional parameter, eg a string.
public class Program
{
public static void Main(string[] args)
{
List<Number> something = new();
Do(something);
}
public static void Do<T>(List<T> list)
{
list.Add(Factory<T>.Create());
}
}
public abstract class Factory<T>
{
private static Object ConcreteF()
{
if (typeof(T) == typeof(Number))
return new ChildGenericNumber();
throw new Exception("");
}
public static T Create()
{
return (Factory<T>)ConcreteF()).Build();
}
protected abstract T Build();
}

Generic lists: The type arguments for method cannot be inferred from the usage in lambdas

I got a problem in C#, giving me an error 'The type arguments for method cannot be inferred from the usage'. Seems that the compiler cannot determine the correct interface, if I derive a generic list from a non-generic one:
Code:
public class SpecialItem : BaseItem
{
public string Title { get; set; }
}
public class BaseItem
{
public string Name { get; set; }
}
public class GenericList<T> : NongenericBaseList, IEnumerable<T>
where T: BaseItem
{
public new T this[int index]
{
get { return _items[index] as T; }
}
public new IEnumerator<T> GetEnumerator()
{
var iter = _items.GetEnumerator();
while (iter.MoveNext())
{
yield return iter.Current as T;
}
}
}
public class NongenericBaseList : IEnumerable<BaseItem>
{
protected List<BaseItem> _items;
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Usage:
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList) // Uses IEnmerable<SpecialItem>, OK!
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList(); // ERROR!
The ForEarch gets the correct Enumerator (SpecialItem), but the lambda does not know what to use (IEnumerable<BaseItem> or IEnumerable<SpecialItem>).
What to do? How can I set IEnumerable<SpecialItem> as 'default' interface? I dont want to explicetly code the type all the time like this:
var l = genericList.ToList<SpecialItem>();
First of all: kudos for providing a self-contained example!
You cannot specify a 'default' interface for type inference. The argument type for ToList<T> cannot be resolved because it is ambiguous, the type implements both IEnumerable<BaseItem> and IEnumerable<SpecialItem>, and both versions are applicable.
Is there a possibility to remove the class NongenericBaseList completely, and use the GenericList<T>instead? That would solve your problem; you can use GenericList<BaseItem> instead of NongenericBaseList
Another option is to reverse the inheritance; make NongenericBaseList empty and deriving from GenericList<BaseItem>.
Thanks to Sriram Sakthivel, he guided me to a solution with a very small overhead. To make things clear I wanted to make sure that:
Both lists, the generic and nongeneric one must be the same object. Therefore I have to derive, not packing in a wrapper.
Both lists must support access via loops (ForEach) and lambdas / extension methods without the need to explicitly typing the class name.
They have to implement IList<T>, so T out is not an option.
In short, the following code must compile without errors:
// Generic
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList)
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList();
// Nongeneric
var nongenericList = genericList as NongenericBaseList;
foreach (var item in nongenericList)
{
Console.WriteLine(item.Name);
}
var nl = nongenericList.ToList();
I came to the conclusion, that this is not possible with the upper code (correct me if that is not true!). The loops are working fine, but either the generic or the nongeneric list does not work with .ToList() or other extension methods, because the compiler cannot inferre the type.
Now I used Sriram Sakthivel tipp, implementing only IEnumerable without <T>. But that allone would make it impossible to use extension methods at all even if you explicitely write the type.
I simply added a property, casting the collection:
public class NongenericBaseList : IEnumerable // Without the T!
{
protected List<BaseItem> _items;
// The property
public IEnumerable<BaseItem> L
{
get { return this as IEnumerable<BaseItem>; }
}
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now I can type:
var nl = nongenericList.L.ToList();
Any better solution would be appreciated!

Determine if a generic type has a corresponding implementation

I have a series of static methods to modify a collection then return the modified collection:
private static IEnumerable<Invoice> ResolveProxies(IEnumerable<Invoice> e) {
// do something to e
return e;
}
private static IEnumerable<Person> ResolveProxies(IEnumerable<Person> e) {
// do something to e
return e;
}
In another part of the application there is a method to decide if a collection is of a certain type, so that it can be converted to that type and have its corresponding ResolveProxies method called:
public static GridModel<T> ToGridModel<T>(this GridModel gridModel) {
// gridModel.Data is just IEnumerable
var collection = gridModel.Data as IEnumerable<T> ?? new List<T>();
return new GridModel<T> {
Data = EvaluateDynamicProxies(collection),
Total = gridModel.Total
};
}
private static IEnumerable<T> EvaluateProxies<T>(IEnumerable<T> collection) {
if (collection is IEnumerable<Invoice>) {
var enumeration = (collection as IEnumerable<Invoice>);
return ResolveProxies(enumeration) as IEnumerable<T>;
}
if (collection is IEnumerable<Person>) {
var enumeration = (collection as IEnumerable<Person>);
return ResolveProxies(enumeration) as IEnumerable<T>;
}
// proxy resolution isn't needed so return the unchanged collection
return collection;
}
Having such repetitive conditional logic is bad code smell. I'm struggling to come up with some way to mark particular types so that I know they have a corresponding proxy resolver method. Something like this perhaps:
public interface IProxyResolver<out T> where T:IEnumerable<T> {
T ResolveProxies();
}
But how would I use this? In effect I need a way to ask the compiler:
Does T have a matching ResolveProxies method?
What is the name of the class or method that resolves proxies for T so that I can get an instance of it and call it?
You could use an inversion of control (IOC) framework. For example, my team uses Castle Windsor. You can register services (usually interfaces) and types that provide the services. It has some nice generics resolution, so you can do things like this:
interface IProxyResolver<T> { /* whatever */ }
class ProxyResolver<T> : IProxyResolver<T> { /* ... */ }
class PersonProxyResolver : ProxyResolver<Person> { }
class InvoiceProxyResolver : ProxyResolver<Invoice> { }
then, you can summon these types like this:
void SomeMethodThatNeedsAProxyResolver<T>(T obj)
{
var resolver = ioc.Resolve<IProxyResolver<T>>();
//...
}
If you've regsitered the classes above, when T is Person or Invoice, you get the correct non-generic subclass of ProxyResolver; if it is any other type, you get the default generic superclass. Of course, you can structure things differently; if you need a specific proxy resolver for every type, that's possible too.
How about using a custom attribute? This is how custom serializers are selected, etc.
You'd start by defining the Attribute class:
public class ProxyResolverAttribute : Attribute {
public Type ResolverType { get; set; }
public ProxyResolver(Type resolverType) { ResolverType = resolverType; }
}
and then put that on the type contained, e.g.
[ProxyResolver(TypeOf(InvoiceProxyResolver))]
public class Invoice ... { ... }
then use reflection to see if the generic type used in the collection specifies a proxy resolver type:
// Untested, beware of bugs
var enumerationGenericType = enumeration.GetType().GetGenericArguments().FirstOrDefault();
var resolverAttribute = enumerationGenericType.GetType().GetCustomAttributes(TypeOf(ProxyResolverAttribute)).FirstOrDefault();
if (resolverAttribute != null) {
var resolverType = resolverAttribute.ResolverType;
// instanciate something of resolverType here
}
EDIT: Reading the comments, if you don't want to apply the attributes to the contained objects, I'd suggest creating custom classes which inherit List and apply the attribute there, e.g.
[ProxyResolver(TypeOf(InvoiceProxyResolver))]
public class InvoiceList : List<Invoice>

Same method that takes a different parameter type?

I know there are very similar questions but im not sure that any of them are exactly what i need. I have 2 methods that do exactly the same thing (so i dont need to override or anything) the only difference is the parameter and return types.
public List<List<TestResult>> BatchResultsList(List<TestResult> objectList)
{
}
public List<List<ResultLinks>> BatchResultsList(List<ResultLinks> objectList)
{
}
is there a neat way of doing this that doesnt involve duplciate code (the types are used inside the method).
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
foreach(T t in objectList)
{
// do something with T.
// note that since the type of T isn't constrained, the compiler can't
// tell what properties and methods it has, so you can't do much with it
// except add it to a collection or compare it to another object.
}
}
and if you need to limit the type of T so that you'll only process specific sorts of objects, make both TestResult and ResultLinks implement an interface, say, IResult. Then:
public interface IResult
{
void DoSomething();
}
public class TestResult : IResult { ... }
public class ResultLinks : IResult { ... }
public List<List<T>> BatchResultsList<T>(List<T> objectList) where T : IResult
{
foreach(T t in objectList)
{
t.DoSomething();
// do something with T.
// note that since the type of T is constrained to types that implement
// IResult, you can access all properties and methods defined in IResult
// on the object t here
}
}
When you call the method, you can of course omit the type parameter, since it can be inferred:
List<TestResult> objectList = new List<TestResult>();
List<List<TestResult>> list = BatchResultsList(objectList);
use generic methods
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
}
when you call it for TestResult:
BatchResultsList<TestResult>(testResultList)
for ResultLinks:
BatchResultsList<ResultLinks>(resultLinksList)
EDIT:
I presume that because it's the same code inside you 2 methods, TestResult & ResultLinks must implement a common interface, let's call it SomeInterface & a common constructor, let's choose the parameterless one:
you would declare and use the method like this:
public List<List<T>> BatchResultsList<T>(List<T> objectList)
where T:SomeInterface, new()
{
List<List<T>> toReturn = new List<List<T>>();
//to instantiate a new T:
T t = new T();
foreach (T result in objectList)
{
//use result like a SomeInterface instance
}
//...
return toReturn;
}
what about
public List<IList> BatchResultsList(List<IList> objectList)
{
}
Generic version:
public List<List<T>> BatchResultsList<T>(List<T> objectList){}

Categories

Resources