Looking for non-type-specific method of handling Generic Collections in c# - c#

My situation is this. I need to run some validation and massage type code on multiple different types of objects, but for cleanliness (and code reuse), I'd like to make all the calls to this validation look basically the same regardless of object. I am attempting to solve this through overloading, which works fine until I get to Generic Collection objects.
The following example should clarify what I'm talking about here:
private string DoStuff(string tmp) { ... }
private ObjectA DoStuff(ObjectA tmp) { ... }
private ObjectB DoStuff(ObjectB tmp) { ... }
...
private Collection<ObjectA> DoStuff(Collection<ObjectA> tmp) {
foreach (ObjectA obj in tmp) if (DoStuff(obj) == null) tmp.Remove(obj);
if (tmp.Count == 0) return null;
return tmp;
}
private Collection<Object> DoStuff(Collection<ObjectB> tmp) {
foreach (ObjectB obj in tmp) if (DoStuff(obj) == null) tmp.Remove(obj);
if (tmp.Count == 0) return null;
return tmp;
}
...
This seems like a real waste, as I have to duplicate the exact same code for every different Collection<T> type. I would like to make a single instance of DoStuff that handles any Collection<T>, rather than make a separate one for each.
I have tried using ICollection, but this has two problems: first, ICollection does not expose the .Remove method, and I can't write the foreach loop because I don't know the type of the objects in the list. Using something more generic, like object, does not work because I don't have a method DoStuff that accepts an object - I need it to call the appropriate one for the actual object. Writing a DoStuff method which takes an object and does some kind of huge list of if statements to pick the right method and cast appropriately kind of defeats the whole idea of getting rid of redundant code - I might as well just copy and paste all those Collection<T> methods.
I have tried using a generic DoStuff<T> method, but this has the same problem in the foreach loop. Because I don't know the object type at design time, the compiler won't let me call DoStuff(obj).
Technically, the compiler should be able to tell which call needs to be made at compile time, since these are all private methods, and the specific types of the objects being passed in the calls are all known at the point the method is being called. That knowledge just doesn't seem to bubble up to the later methods being called by this method.
I really don't want to use reflection here, as that makes the code even more complicated than just copying and pasting all the Collection<T> methods, and it creates a performance slowdown. Any ideas?
---EDIT 1---
I realized that my generic method references were not displaying correctly, because I had not used the html codes for the angle brackets. This should be fixed now.
---EDIT 2---
Based on a response below, I have altered my Collection<T> method to look like this:
private Collection<T> DoStuff<T>(Collection<T> tmp) {
for (int i = tmp.Count - 1; i >= 0; i--) if (DoStuff(tmp[i]) == null) tmp.RemoveAt(i);
if (tmp.Count == 0) return null;
return tmp;
}
This still does not work, however, as the compiler cannot figure out which overloaded method to call when I call DoStuff(tmp[i]).

You need to pass the method you want to call into the generic method as a parameter. That way the overload resolution happens at a point where the compiler knows what types to expect.
Alternatively, you need to make the per-item DoStuff method generic (or object) to support any possible item in the collection.
(I also separated the RemoveItem call from the first loop, so that it isn't trying to remove an item from the same list being iterated.)
private Collection<T> DoStuff<T>(Collection<T> tmp, Func<T, T> stuffDoer)
{
var removeList = tmp
.Select(v => stuffDoer(v))
.Where(v => v == null)
.ToList();
foreach (var removeItem in removeList) tmp.Remove(removeItem);
if (tmp.Count == 0) return null;
return tmp;
}
private class ObjectA { }
private class ObjectB { }
private string DoStuff(string tmp) { return tmp; }
private ObjectA DoStuff(ObjectA tmp) { return tmp; }
private ObjectB DoStuff(ObjectB tmp) { return tmp; }
Call using this code:
var x = new Collection<ObjectA>
{
new ObjectA(),
new ObjectA(),
null
};
var result = DoStuff(x, DoStuff);

Something like this?:
private Collection DoStuff<T>(Collection tmp)
{
// This will probably assert as you are modifying a collection while looping in it.
foreach (T obj in tmp) if (DoStuff(obj) == null) tmp.Remove(obj);
if (tmp.Count == 0) return null;
return tmp;
}
Where T is the type of the object in the collection.
Please note that you have a line that will most likely assert. SO:
private Collection DoStuff<T>(Collection tmp)
{
// foreach doesn't work if you are modifying the collection.
// Looping backward with an index, so we never encounter an invalid index.
for (int i = tmp.Count - 1; i >= 0; i--) if (DoStuff(tmp[i]) == null) tmp.Remove(tmp[i]);
if (tmp.Count == 0) return null;
return tmp;
}
But at this point... Why make it generic, since you are not using T anymore?
private Collection DoStuff(Collection tmp)
{
// DoStuff can be generic, but you shouldn't need to explicitly pass it a type...
for (int i = tmp.Count - 1; i >= 0; i--) if (DoStuff(tmp[i]) == null) tmp.Remove(tmp[i]);
if (tmp.Count == 0) return null;
return tmp;
}

Related

adding function result to list while checking it

As I do that often enough i was wondering if there is a neat way to skip using a variable. I have a function that returns a List of unknown length. I want to add the result to another list and also know if i got returned an empty list. I could save the function result in a variable and see if its empty and otherwise add it to the list. I just was thinking if this could be done more elegantly.
I also could do:
myList.AddRange(getFiles(path));
if(getFiles(path).Count == 0)
{
doSomething();
}
getFiles being an example function that returns a list of files at a path
That way however I have to call the function twice.
This is more of a programming style question as I am quite unexperienced. Should one make a "tmp" variable everytime this happens?
Make this extension method:
public static int AddRangeEx<T>(this List<T> target, IEnumerable<T> items)
{
int result = items.Count();
if( result > 0 ) target.AddRange(items);
return result;
}
And then you'll be able to write code like this:
if(myList.AddRangeEx(getfiles(path)) > 0)
{
doSomething();
}
Alternatively, if you're concerned about side effects of the extra Count() call (even just performance side effects, but there are lots of ways to get an IEnumerable that can only run one time), you could build the extension method this way:
public static int AddRangeEx<T>(this List<T> target, IEnumerable<T> items)
{
int result = 0;
foreach (T item in items)
{
target.Add(item);
result++;
}
return result;
}
Which isn't really any different than what AddRange() and Count() were already doing.
As a bonus, you can overload the extension method for improved performance on types that already know the count:
public static int AddRangeEx<T>(this List<T> target, T[] items)
{
if (items.Length > 0)
target.AddRange(items);
return items.Length;
}
It kind of makes me sad the built-in AddRange() method doesn't already do this for us.
The first choice is to just store a local variable
var files = getFiles(path);
myList.AddRange(files);
if(files.Count == 0)
{
doSomething();
}
The second choice would be this
var count = myList.Count
myList.AddRange(getFiles(path));
if(myList.Count > count)
{
doSomething();
}

How to avoid losing values with List's

I have the following method :
private static Tuple<List<int>, bool> GetTurns(List<int> possibleTurns, IList<int> currentLine)
{
List<int> localPossibleTurns = possibleTurns;
foreach (var passedTurn in passedTurns)
{
for (int j = 0; j < localPossibleTurns.Count; j++)
{
int indexOfNewNumber = currentLine.IndexOf(localPossibleTurns[j]);
if (localPossibleTurns[j] == passedTurn.Item1)
{
if (indexOfNewNumber + 1 == passedTurn.Item2 || indexOfNewNumber == passedTurn.Item2)
{
localPossibleTurns.RemoveAt(j);
}
}
}
}
return localPossibleTurns.Count == 0
? new Tuple<List<int>, bool>(localPossibleTurns, false)
: new Tuple<List<int>, bool>(localPossibleTurns, true);
}
and using it at this line :
if (!GetTurns(possibleRoutes, secondLine).Item2)
{
//do something
}
whenever it reaches that point it passes the possibleRoutes List into the method and since the list is reference type whenever a value is removed from the one declared in the method GetTurns - localPossibleTurns same happens to the possibleRoutes list. How can I avoid this and change the values of possibleRoutes only when I do possibleRoutes = GetTurns(possibleRoutes, secondLine).Item1; ?
Just assigning it to a new variable does not create a new list. If you want a copy you can use possibleTurns.ToList() or better new List<int>(possibleTurns). I prefer the latter for readability regarding object creation and because someday the might change the code of ToList() for performance gains to first check the type and then perform a simple cast.
public static List<T> ToList<T>(this IEnumerable<T> enumerable)
{
if (enumerable is List<T>)
return (List<T>) enumerable;
....
You are modifying the collection passed in as a parameter.
You can create a new collection to work with inside the method using Linq ToList:
List<int> localPossibleTurns = possibleTurns.ToList();

Unity3d from a list, get only entities of specific component type

I know that if I have something like
Component tmp = (myClass)gameObject.GetComponent<myClass>();
can return either a null value, or an instance of the typed "myClass" if it exists on my specific game object. Now, lets assume I have an array of objects from a Physics Sphere Capture of a given radius. I have 20 game objects returned.
How can I create a routine to only return those game objects that have a component of so I don't have to write my own iterator over and over. Again being generics because in one area I may want another and yet another place . I don't want to be throwing typecasting all over to make the readability a pain.
FEEDBACK (per Ciprian's answer)
I tried your approach verbatim and was not getting any that were of the "Class" I wanted even though it was an attached component. So, I tried to modify the routine slightly. First, ensure a proper "GameObject". Then from that, try to call the GameObject's .GetComponent<T>(). but that is causing an error, even though the <T> is the same type I am looking for via get Component.
public static IEnumerable<T> GetItemsAsT<T>(this object[] objects)
where T:class
{
GameObject gObj;
foreach(var obj in objects)
{
if( obj is GameObject )
{
gObj = (GameObject)obj;
if( gObj.GetComponent<T>() != null )
{
Debug.Log ( "Found via IEnumerable" );
yield return gObj.GetComponent<T>();
}
}
}
yield break;
}
Per slight revision to Ciprian's answer.
Error CS0311: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'UnityEngine.GameObject.GetComponent<T>()'. There is no implicit reference conversion from 'T' to 'UnityEngine.Component'. (CS0311) (Assembly-CSharp)
Right now I think I understood your problem so this is why I post as a separate answer.
You have a composite object, and you want to call a custom action based on a mix of custom class "attributes" that exist in a game object.
public static IEnumerable<T> GetItemsAsT<T>(this GameObject[] objects)
where T:UnityEngine.Component
{
foreach(var obj in objects)
{
var t = obj.GetComponent<T>();
if(t != null)
yield return t;
}
yield break;
}
I updated the changes and remove the unnecesary casts from your answer. The single important changes from the questions are:
use GameObject[] array to not make your casts by hand
use where T:Component instead of T:class
I understood that you need two code cases that can be implemented to an array of object:
static class GenericUtils
{
public static IEnumerable<T> GetItemsAsT<T>(this object[] objects)
where T:class
{
foreach(var obj in objects)
{
var t = obj as T;
if(t != null)
yield return t;
}
yield break;
}
public static IEnumerable<T> GetItemsWhere<T>(this object[] objects, Predicate<T> predicate)
where T:class
{
foreach(var tObj in objects.GetItemsAsT<T>())
{
if(predicate(tObj))
{
yield return tObj;
}
}
yield break;
}
}
To use them, you can either get let's say a list of circles:
items.GetItemsAsT<Circle>();
or use a predicate to filter them:
items.GetItemsWhere<Circle>(c => c.Radius < 30);
All items are IEnumerable so if you need to convert them to array, use the .ToArray(), or to use them as a List use .ToList()
Later
If you are familiar with Linq, you can use just the first method and later use Linq combined functions so the last line of code you can rewrite as:
items.GetItemsAsT<Circle>().Where(c => c.Radius < 30);
Also, if your name GetItemsAsT is verbose, chose just a shorter name for them: AsT.

Calculating Count for IEnumerable (Non Generic)

Can anyone help me with a Count extension method for IEnumerable (non generic interface).
I know it is not supported in LINQ but how to write it manually?
yourEnumerable.Cast<object>().Count()
To the comment about performance:
I think this is a good example of premature optimization but here you go:
static class EnumerableExtensions
{
public static int Count(this IEnumerable source)
{
int res = 0;
foreach (var item in source)
res++;
return res;
}
}
The simplest form would be:
public static int Count(this IEnumerable source)
{
int c = 0;
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
c++;
}
return c;
}
You can then improve on this by querying for ICollection:
public static int Count(this IEnumerable source)
{
var col = source as ICollection;
if (col != null)
return col.Count;
int c = 0;
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
c++;
}
return c;
}
Update
As Gerard points out in the comments, non-generic IEnumerable does not inherit IDisposable so the normal using statement won't work. It is probably still important to attempt to dispose of such enumerators if possible - an iterator method implements IEnumerable and so may be passed indirectly to this Count method. Internally, that iterator method will be depending on a call to Dispose to trigger its own try/finally and using statements.
To make this easy in other circumstances too, you can make your own version of the using statement that is less fussy at compile time:
public static void DynamicUsing(object resource, Action action)
{
try
{
action();
}
finally
{
IDisposable d = resource as IDisposable;
if (d != null)
d.Dispose();
}
}
And the updated Count method would then be:
public static int Count(this IEnumerable source)
{
var col = source as ICollection;
if (col != null)
return col.Count;
int c = 0;
var e = source.GetEnumerator();
DynamicUsing(e, () =>
{
while (e.MoveNext())
c++;
});
return c;
}
Different types of IEnumerable have different optimal methods for determining count; unfortunately, there's no general-purpose means of knowing which method will be best for any given IEnumerable, nor is there even any standard means by which an IEmumerable can indicate which of the following techniques is best:
Simply ask the object directly. Some types of objects that support IEnumerable, such as Array, List and Collection, have properties which can directly report the number of elements in them.
Enumerate all items, discarding them, and count the number of items enumerated.
Enumerate all items into a list, and then use the list if it's necessary to use the enumeration again.
Each of the above will be optimal in different cases.
I think the type chosen to represent your sequence of elements should have been ICollection instead of IEnumerable, in the first place.
Both ICollection and ICollection<T> provide a Count property - plus - every ICollection implements IEnumearable as well.

intro to lambda/anonymous functions

I have this function from a plugin (from a previous post)
// This method implements the test condition for
// finding the ResolutionInfo.
private static bool IsResolutionInfo(ImageResource res)
{
return res.ID == (int)ResourceIDs.ResolutionInfo;
}
And the line thats calling this function:
get
{
return (ResolutionInfo)m_imageResources.Find(IsResolutionInfo);
}
So basically I'd like to get rid of the calling function. It's only called twice (once in the get and the other in the set). And It could possible help me to understand inline functions in c#.
get
{
return (ResolutionInfo)m_imageResources.Find(res => res.ID == (int)ResourceIDs.ResolutionInfo);
}
Does that clear it up at all?
Just to further clear things up, looking at reflector, this is what the Find method looks like:
public T Find(Predicate<T> match)
{
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}
So as you can see, it loops through the collection, and for every item in the collection, it passes the item at that index to the Predicate that you passed in (through your lambda). Thus, since we're dealing with generics, it automatically knows the type you're dealing with. It'll be Type T which is whatever type that is in your collection. Makes sense?
Just to add , does the "Find" Function on a list (which is what m_imageresources is) automatically pass the parameter to the IsResoulutionInfo function?
Also, what happens first the cast or the function call?

Categories