0

I'm trying to refactor the below into a generic function; the code sample below works for me if type is a specified in the function declaration. However, it fails when I try to use T.

I get an IENumerable-like object containing generic objects back from an external application, and from this want to filter out those that are of the specific type in question.

For context, these are geometric features selected on screen by the user prior to the code running. I need to validate that the correct type of thing has been picked, and return those things in a clean list.

Initial code with defined type that works:

    public static List<Point> GetSelectedPoints()
    {
        List<Point> tmp = new List<Point>();

        Selection oSel = GetSelectionObject();

        for (int i = 1; i <= oSel.Count; i++)
        {
            try
            {
                if (oSel.Item(i).Value is Point)
                {
                    Point P = (Point)oSel.Item(i).Value;
                    tmp.Add(P);
                }
            }
            catch
            {
                throw new Exception("An error occurred whilst retrieving the selection");
            }
        }

        return tmp;
    }

Here the attempt to use T:

    static public List<T> GetThisTypeFromSelection<T>()
    {

        Selection osel = GetSelectionObject();
        List<T> tmp= new List<T>();
        for(int i = 1; i<=osel.Count ; i++)
        {
            if (osel.Item(i).Value is T)
            {
                T thing = (T)osel.Item(i).Value;
                tmp.Add(tmp);
            }
        }
        return tmp;
    }

osel.Item(i).Value.GetType() returns a "System.__ComObject"... Which is not helpful.

The object model of the external application is such that everything is derived from a single base class, with many layers of subclassing, something like this:

    public class Base
{}

public class Geometry2d : Base
{ }
public class Line : Geometry2d
{ }
public class Circle : Line
{ }
public class Face : Geometry2d
{ }
public class PlanarFace : Face
{ }
public class CylindricalFace : Face
{ }
public class PlanarFaceDefinedThroughX : PlanarFace
{ }
public class PlanarFaceDefinedThroughY : PlanarFace
{ }
etcetera...

So, The selection object (while also deriving from base) returns a list of base object which could be...pretty much anything.

Depending on the application for this function, I might want to get, for example, everything that's a "Face" or derivative, or maybe just the PlanarFaces, or maybe even just the PlanarFaceDefinedThroughXs.

The selection object looks like this:


Update based on comments (kudos to mm8 pointing in the right direction)

    static public List<T> GetThisTypeFromSelection<T>()
    {

        Selection osel = GetSelectionObject();
        List<Base> listA = new List<Base>();
        for(int i = 1; i<=osel.Count ; i++)
        {
            CATBaseDispatch CbD = osel.Item(i).Value;
            listA.Add(CbD);
        }
        List<T> results = listA.Select(x => x).OfType<T>().ToList();

        return results;
    }

This approach seems to successfully filter out the right object types - but the returned list still shows them as COM objects...

enter image description here

ErosRising
  • 165
  • 7
  • [This](https://stackoverflow.com/questions/457676/check-if-a-class-is-derived-from-a-generic-class) question might help – MindSwipe Jan 15 '19 at 10:07
  • If you're getting `System.__ComObject` as the type, then it sounds like you have some really old legacy component that you're trying to interop with. What exactly does `GetSelectionObject()` do and return? – DavidG Jan 15 '19 at 10:18
  • @MindSwipe I've just tried that and got no joy - It seems that despite my assumption, the "BaseType" for the objects actually returns null. – ErosRising Jan 15 '19 at 10:43
  • @DavidG It returns a Selection object from the external application – ErosRising Jan 15 '19 at 10:46
  • That's not helpful, I can tell that from the code. What is a selection object though? – DavidG Jan 15 '19 at 10:46
  • @ErosRising: Does this satisfy your requirements? `var points = oSel.Item.Select(x => x.Value).OfType().ToList();` – mm8 Jan 15 '19 at 10:54
  • @DavidG Sorry, I'm not trying to sound rude. There's just not much more I can say... I've added a snip of its' properties, and intellisense reveals functions to add/remove/access/copy/paste/delete items within it – ErosRising Jan 15 '19 at 10:57
  • My question revolves around what `oSel.Item(i).Value` actually is. If `GetType` tells you it's a COM object then it's not clear how the first non-generic code you have above actually works. – DavidG Jan 15 '19 at 11:16
  • Could you use `IsAssignableFrom` here? – Robin Bennett Jan 15 '19 at 11:22
  • Part of my troubles coding for this application is that stuff that looks like it should work, doesn't, and stuff that looks like it shouldn't, does... – ErosRising Jan 15 '19 at 11:24
  • `stuff that looks like it should work, doesn't, and stuff that looks like it shouldn't, does` - that's COM for you! – Robin Bennett Jan 15 '19 at 11:28

1 Answers1

1

If your Selection implements IEnumerable you could use Linq's OfType to filter items of desired type.

Pablo notPicasso
  • 3,031
  • 3
  • 17
  • 22