Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Sedro
Dec 31, 2008
If it's COM, probably an interop assembly to a type library. Or are we talking about COM serial ports?

Adbot
ADBOT LOVES YOU

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.

ljw1004 posted:

Is it a .NET assembly rather than a plain old win32 DLL? Is it really "your library"? If so, I wonder if MEF might work. It's entire purpose is to allow loose coupling between assemblies in this sort of way.

My program is .NET, the driver is a win32-style DLL that is supplied by the hardware manufacturer. I don't have access to the driver source code so I think MEF is out in this case. Thanks for the suggestion though.

Sedro posted:

If it's COM, probably an interop assembly to a type library. Or are we talking about COM serial ports?

Yep, it's COM as in Common Object Model, not as in COM1 serial port.


At this point I'm thinking about hiding the actual driver code behind some interface, and then creating a do-nothing placeholder class that implements that same interface. At startup I'd attempt to create the actual driver class but if that process fails due to the DLL not existing I'd return the placeholder class instead. I usually abstract all my hardware devices as interfaces anyway for testing purposes so making the placeholder class won't really even be much extra work.

Smugdog Millionaire
Sep 14, 2002

8) Blame Icefrog
Wrap the driver in your own .NET assembly and use MEF to dynamically load it?

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.

Smugdog Millionaire posted:

Wrap the driver in your own .NET assembly and use MEF to dynamically load it?

I'd still have to probe for the existence of the driver in the wrapper code and fall back gracefully somehow if it doesn't exist, so I'm not sure that this would solve the problem so much as it would move it to another place.

Let me know if I'm wrong though, I'm no MEF expert so there may be something I'm missing.

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.
I'm an experienced programmer with backgrounds in Perl, Python, Ruby, C and a few other languages looking to get up to speed with .NET and the CLR in as little time as possible for a project I'm working on. Specifically, I want to focus on conventions and the way that .NET developers do things that might not be implicit in the language itself. Where should I start?

csammis
Aug 26, 2003

Mental Institution
Conventions are specific to language and not .NET in general. Which language are you working with for your project? C#, F#, VB.NET, one of the others which targets the CLR?

Vulture Culture
Jul 14, 2003

I was never enjoying it. I only eat it for the nutrients.

csammis posted:

Conventions are specific to language and not .NET in general. Which language are you working with for your project? C#, F#, VB.NET, one of the others which targets the CLR?
Sorry, C#, though I'm interested in learning F# at some point as well.

Mr. Crow
May 22, 2008

Snap City mayor for life
What would be the fastest/best way to implement a Tree View in WinForms? Was reading on SO you could create a WPF TreeView control and use ElementHost to have the WPF control in WinForms but I'm not familiar with WPF or creating controls, would this be fairly simple or not so much?

Sedro
Dec 31, 2008
WinForms doesn't have a TreeView? WPF's TreeView is very limited so I wouldn't recommend using that (even in WPF). It wouldn't be simple to create one with either technology. The best/fastest way is to find one off the shelf.

Dietrich
Sep 11, 2001

Mr. Crow posted:

What would be the fastest/best way to implement a Tree View in WinForms? Was reading on SO you could create a WPF TreeView control and use ElementHost to have the WPF control in WinForms but I'm not familiar with WPF or creating controls, would this be fairly simple or not so much?

I use the winforms treeview control, which is pretty ok.

ljw1004
Jan 18, 2005

rum

PDP-1 posted:

I could dynamically load the DLL using Assembly.LoadFrom("myLibrary.dll") but that's really ugly since the IDE doesn't have a way to know the internal DLL types which would make programming the interface painful as I'd have to call everything via reflection and manually cast.

That's not quite true... Here's a different idea.

(1) Develop your application in the way you did up until now, by adding a reference. So at least you can develop using intellisense and type-checking.

(2) But then, use the new "dynamic" pseudo-type. It's entire purpose is to make it easier to late-bind to different assemblies.

code:
dynamic d = GetTheCOMobject();
d.Foo();
d.Bar = 15;
Essentially this is way of doing reflection, but under the hood, so that your source code stays clean.

Smugdog Millionaire
Sep 14, 2002

8) Blame Icefrog

PDP-1 posted:

I'd still have to probe for the existence of the driver in the wrapper code and fall back gracefully somehow if it doesn't exist, so I'm not sure that this would solve the problem so much as it would move it to another place.

Let me know if I'm wrong though, I'm no MEF expert so there may be something I'm missing.

I guess I misunderstood the problem statement. I thought you had control over driver distribution and could distribute the .NET wrapper along with it.

genki
Nov 12, 2003

Mr. Crow posted:

What would be the fastest/best way to implement a Tree View in WinForms? Was reading on SO you could create a WPF TreeView control and use ElementHost to have the WPF control in WinForms but I'm not familiar with WPF or creating controls, would this be fairly simple or not so much?
Uh, use the builtin WinForms TreeView?
http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.aspx

It's not the most flexible and wonderful treeview in the world, but you haven't specified any functionality that would make it ineligible for use...

edit: I guess this was mentioned a few times before me. :v: slow typing.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.

ljw1004 posted:

That's not quite true... Here's a different idea.

(1) Develop your application in the way you did up until now, by adding a reference. So at least you can develop using intellisense and type-checking.

(2) But then, use the new "dynamic" pseudo-type. It's entire purpose is to make it easier to late-bind to different assemblies.

code:
dynamic d = GetTheCOMobject();
d.Foo();
d.Bar = 15;
Essentially this is way of doing reflection, but under the hood, so that your source code stays clean.

When I wrote that stuff you quoted I was operating under the incorrect assumption that just having a reference in my project would cause the application to resolve the COM interface at start-up. No idea why I thought that was true, but realizing that the COM references only kick in when you first interact with the driver makes everything simpler. I can just try/catch around the first instantiation of the driver and handle things from there.

The idea of using a dynamic variable is pretty interesting since the final version of the code wouldn't need specific references to anything at all. I'll have to think about it a bit, but it could wind up being more portable.

Thanks to everyone for the suggestions and help!

e:

Smugdog Millionaire posted:

I guess I misunderstood the problem statement. I thought you had control over driver distribution and could distribute the .NET wrapper along with it.

Yeah it's a bit of an unusual situation in that the application should be usable whether or not a particular bit of hardware is plugged into a USB port. If the hardware isn't present I don't want to require the driver to be present either. Most of the users will never have the hardware connected so forcing them to install drivers would just be confusing for them.

PDP-1 fucked around with this message at 22:50 on Nov 15, 2011

Mr. Crow
May 22, 2008

Snap City mayor for life

genki posted:

Uh, use the builtin WinForms TreeView?
http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.aspx

It's not the most flexible and wonderful treeview in the world, but you haven't specified any functionality that would make it ineligible for use...

edit: I guess this was mentioned a few times before me. :v: slow typing.

Well I was hoping for an easily implemented more flexible approach so I wouldn't have to re-write it later when we eventually move it to the end-user GUI, but I don't have the time to spend on it at the moment, just need a basic TreeView for internal use atm.

And now I'm running into another issue, how do I get the generic type of a parent?

Basically I have child : parent<T> and I want T. I can use child.GetType().BaseType.GetGenericArguments() but that is annoying because it has a bunch of assumptions.

Mr. Crow fucked around with this message at 00:52 on Nov 16, 2011

Dr Monkeysee
Oct 11, 2002

just a fox like a hundred thousand others
Nap Ghost
I can't imagine how else you'd do it. "type" in parent<type> isn't the parent's type, the parent's type is parent<type>. Imagine if you had parent<type1, type2> instead, which one would you expect to get as the parent "type"?

Mr. Crow
May 22, 2008

Snap City mayor for life
Was copy/pasting code and not what is actually going on, so I'm not trying to get the base of the parent, I'm getting the base of the child (so in our example, parent). Check edit.

Also I'd expect to get type1 and type2, GetGenericArguments returns an array.

Basically I'd like a way to do is, however many layers up the hierarchy, there is eventually a parent<T> that I'd like to get. The problem is right now it's assumed it's the immediate parent (which in this case it is and I'm fine with leaving it like that for now).

Sedro
Dec 31, 2008
You can walk up the inheritance hierarchy until you hit a parent:
code:
static Type[] GetParentTypeParams(Type type)
{
    if (type == null)
        return null;
    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Parent<>))
        return type.GetGenericArguments();
    else
        return GetParentTypeParams(type.BaseType);
}

Scaramouche
Mar 26, 2001

SPACE FACE! SPACE FACE!

Yeah what he said. There really isn't an elegant way to deal with WinForms Tree control hierarchy (e.g. that doesn't involve a for next/while per level) unless you have the original hierarchy definition in another format (e.g. XML).

Slurps Mad Rips
Jan 25, 2009

Bwaltow!

PDP-1 posted:

I'd still have to probe for the existence of the driver in the wrapper code and fall back gracefully somehow if it doesn't exist, so I'm not sure that this would solve the problem so much as it would move it to another place.

Let me know if I'm wrong though, I'm no MEF expert so there may be something I'm missing.

You might be able to try some trickery within the wrapper code by delay loading the native code, and using the __pfnDliFailureHook2 to handle when it can't be loaded properly, and then you can gracefully fallback onto whatever you need to.

However, the documentation on this is extremely sparse, so you may want to look for an alternative.

edit: Actually ignore this, I'm not really paying attention it seems.

Zhentar
Sep 28, 2003

Brilliant Master Genius

Mr. Crow posted:

Basically I have child : parent<T> and I want T.

Can you modify the parent class? You could just add a method to Parent<T> that returns typeof(T).

Orzo
Sep 3, 2004

IT! IT is confusing! Say your goddamn pronouns!

Zhentar posted:

Can you modify the parent class? You could just add a method to Parent<T> that returns typeof(T).
I think he means to do it in an abstract way for all cases...adding that method is pretty shoddy design.

Mr. Crow
May 22, 2008

Snap City mayor for life

Orzo posted:

I think he means to do it in an abstract way for all cases...adding that method is pretty shoddy design.

Basically, although now a similar question (same piece of code), how do I cast a generic?

Again, I've created an instance of the T from before, but now I'm trying to actually wire the two together.

Parent (which is a collection) has the following, abstract Parent<T> where T : ICommon, now that I've got a concrete item T, how do I add T to the Parent collection? ((Parent<ICommon>) parent).Add(T) compiles but then throws cast exceptions.

genki
Nov 12, 2003

Mr. Crow posted:

Basically, although now a similar question (same piece of code), how do I cast a generic?

Again, I've created an instance of the T from before, but now I'm trying to actually wire the two together.

Parent (which is a collection) has the following, abstract Parent<T> where T : ICommon, now that I've got a concrete item T, how do I add T to the Parent collection? ((Parent<ICommon>) parent).Add(T) compiles but then throws cast exceptions.
I know this is possible but unfortunately I can't look up/test the specifics atm.

I am curious as to exactly how this frankenstein-type requirement came to be? What exactly is the use case such that you need to be able to do this kind of thing? Does it involve a 3rd party, by any chance? I would hate to think any internal design would allow this kind of reflection nonsense to be required (though I suppose in a large enough company, it's entirely possible...)

I also have to assume that speed/performance aren't major limitations?

Zhentar
Sep 28, 2003

Brilliant Master Genius

genki posted:

I know this is possible but unfortunately I can't look up/test the specifics atm.

It's not possible to cast parent to Parent<ICommon> unless T is ICommon. You can only use covariance with interfaces, and even then you shouldn't be able to make something with an Add function covariant.

I don't know if there's a way to cast it to Parent<T>, but it definitely sounds to me like the kind of question you shouldn't need to ask in the first place.

Orzo
Sep 3, 2004

IT! IT is confusing! Say your goddamn pronouns!
Yeah...I might be reading this wrong, but why not just cast to Parent<T>? Since T must implement ICommon, it should have the Add method available.

boo_radley
Dec 30, 2005

Politeness costs nothing
completely the wrong thread! n/m.

Mr. Crow
May 22, 2008

Snap City mayor for life

Orzo posted:

Yeah...I might be reading this wrong, but why not just cast to Parent<T>? Since T must implement ICommon, it should have the Add method available.

You'd think that (and they do) but it doesn't let me do that, it was the first thing I tried (hence the comment about having the ICommon constraint). Very annoying to be sure and I was hoping someone would answer why it doesn't work, among any other bits of info.

genki posted:

I know this is possible but unfortunately I can't look up/test the specifics atm.

I am curious as to exactly how this frankenstein-type requirement came to be? What exactly is the use case such that you need to be able to do this kind of thing? Does it involve a 3rd party, by any chance? I would hate to think any internal design would allow this kind of reflection nonsense to be required (though I suppose in a large enough company, it's entirely possible...)

I also have to assume that speed/performance aren't major limitations?

Yes it half involves a 3rd party standard. Basically according to the spec they have collections defined as separate entities (which translates to like 30 separate wrapper classes for a list), so I have a collection base Parent<T> that all the wrapper classes inherit from, and the T tells me what the actual lists objects are supposed to be. Supposed to be being the crucial problem, I can't genericize everything/list itself because I don't actually know what kind of data I'm going to be reading in and can't assume it's valid data, so in the base the list is just a List<ICommon> so it can be validated later. It's for convenience in other area's (like it should have been here).

Orzo
Sep 3, 2004

IT! IT is confusing! Say your goddamn pronouns!
I'm actually having a little trouble following the way your pieces fit together Mr Crow...could you paste something more complete on pastebin or something? Maybe like a simplified version of your system.

Dr Monkeysee
Oct 11, 2002

just a fox like a hundred thousand others
Nap Ghost

Mr. Crow posted:

Supposed to be being the crucial problem, I can't genericize everything/list itself because I don't actually know what kind of data I'm going to be reading in and can't assume it's valid data, so in the base the list is just a List<ICommon> so it can be validated later. It's for convenience in other area's (like it should have been here).

So it's a List<ICommon> (or something much like it) which means everything in it is guaranteed to be an ICommon. But then it sounds like the collection contains heterogeneous implementations of ICommon, of which you need to know the actual type (or parent type) after pulling it out of the collection? Am I getting that right? This sounds like a disaster of a design.

Like you know you have an ICommon but in case A you need an ICommon that is also a FooParent but in case B you need an ICommon that is also a BarParent and that information is lost by the collection since everything is typed to ICommon. Basically it's equivalent to using an old school ArrayList and you need to re-discover the type information of each element as it's used?

genki
Nov 12, 2003

Zhentar posted:

It's not possible to cast parent to Parent<ICommon> unless T is ICommon. You can only use covariance with interfaces, and even then you shouldn't be able to make something with an Add function covariant.

I don't know if there's a way to cast it to Parent<T>, but it definitely sounds to me like the kind of question you shouldn't need to ask in the first place.
Sorry, I should have been more specific. I know with reflection it's possible to craft your code such that you can successfully complete the Add operation as intended, but I'm not saying it's possible to cast to Parent<ICommon>.

If no one has a solution by tomorrow morning, I should be able to post one up by then.

At least, assuming I'm remembering correctly (pretty sure I've dealt with this issue before). (Which, coincidentally, is also the reason I agree that it's a situation that a developer shouldn't have to deal with in the first place, haha...)

PhonyMcRingRing
Jun 6, 2002
Ok, I'm a bit lost on the discussion here. Is the child a class that derives from Parent<T>, or are we talking about a child object in a parent object trying to find its parent? If it's the first, why not just add an Add<T> method to Parent<T>? The derived class wouldn't lose the type safety of the T there.

If it's the latter, why not have the child raise an event that the parent can listen for? Then the parent can deal with casting the object to whatever T is.

Or you can do:
code:
public interface IParent {
	void Add(object obj);
}

public abstract class Parent<T> : IParent {
   // Regular accessor:
   public void Add(T obj) {
       // Do whatever it is you do
   }

   // Explicitly implement the interface
   void IParent.Add(object obj) {
       this.Add((T)obj);
   }
}
Which will let you do ((IParent)parent).Add(obj)

Or you can do the fun dynamic way which won't get checked until runtime:
code:
dynamic butts = GetParent();
butts.Add(obj);

PhonyMcRingRing fucked around with this message at 00:42 on Nov 17, 2011

Mr. Crow
May 22, 2008

Snap City mayor for life
This is basically the whole situation http://pastebin.com/E0Fzp0F4

Monkeyseesaw posted:

So it's a List<ICommon> (or something much like it) which means everything in it is guaranteed to be an ICommon. But then it sounds like the collection contains heterogeneous implementations of ICommon, of which you need to know the actual type (or parent type) after pulling it out of the collection? Am I getting that right? This sounds like a disaster of a design.

Like you know you have an ICommon but in case A you need an ICommon that is also a FooParent but in case B you need an ICommon that is also a BarParent and that information is lost by the collection since everything is typed to ICommon. Basically it's equivalent to using an old school ArrayList and you need to re-discover the type information of each element as it's used?

We have to create and return error files (that give detailed information) so we can't just discard erroneous data while we're initially reading the file in. Basically there are three types of classes to account for; Lists, "Primitives", and "Everything else", and everything is an ICommon. Everything of a specific type is generally identical, except for the specific validations you have to do on them; and in the case of "Everything else" types, they have variable "children" (wrt to a tree) that can be any of the three types (list, primitive, other), but are otherwise identical.

I had nothing to do with designing the class structure or file structure that is based off said structure that we read to/from, as mentioned its a 500 y/o industry standard that everyone and their mother uses. I'm just moving it from pseudo-code to C#.

brainfizz
Nov 1, 2010

Mr. Crow posted:

This is basically the whole situation http://pastebin.com/E0Fzp0F4


We have to create and return error files (that give detailed information) so we can't just discard erroneous data while we're initially reading the file in. Basically there are three types of classes to account for; Lists, "Primitives", and "Everything else", and everything is an ICommon. Everything of a specific type is generally identical, except for the specific validations you have to do on them; and in the case of "Everything else" types, they have variable "children" (wrt to a tree) that can be any of the three types (list, primitive, other), but are otherwise identical.

I had nothing to do with designing the class structure or file structure that is based off said structure that we read to/from, as mentioned its a 500 y/o industry standard that everyone and their mother uses. I'm just moving it from pseudo-code to C#.

Can you change the List<ICommon> to a Dictionary<ICommon, ParentType>? That would solve all you problems.

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:
Your main problem is this line:
((ListBase<ICommon>) parent).Add(child)

[edit]
To clarify, the cast is the problem:
((ListBase<ICommon>) parent)

The Add(child) is not an issue, because your code throws an InvalidCastException before it even gets there.
[/edit]

Parent is NOT a ListBase<ICommon>, it's a ListBase<T>, that T is constrained to implement ICommon is irrelevant as ListBase<T> does not derive from ListBase<ICommon>.

Since you're using reflection to determine T, there's no really easy way to make that cast work. It can be done by some other fuckery, but that solution would probably be more at home in the coding horrors thread than here.

But, like others have already suggested, this should work:
code:
dynamic d = parent;
d.Add(child);
Couple of other things:

code:
public abstract ListBase<T> : SUPERBASEWHATSUP where T : ICommon
{
  private List<ICommon> list;
 
  public void Add(ICommon item)
  {
    if (item != null)
      list.Add(item)
  }
}
Why is ListBase a generic if you're allowing any type of ICommon? Shouldn't it be like this?

code:
public abstract ListBase<T> : SUPERBASEWHATSUP where T : ICommon
{
  private List<T> list;
 
  public void Add(T item)
  {
    if (item != null)
      list.Add(item)
  }
}
Or you could simply remove the generic argument from ListBase and solve your casting problem, as well as the problems of determining what T is in the first place.

code:
SUPERBASEWHATSUP child = (SUPERBASEWHATSUP) Activator.CreateInstance(listType[0]);
Why do you have a constraint of ICommon on ListBase<T> when your code always assumes it's a SUPERBASEWHATSUP? Either T should be constrained to SUPERBASEWHATSUP or this should be a cast to ICommon.

Also, if you really need to keep ListBase<T>'s generic parameter, consider adding new() to ListBase<T>'s constraint. Your code already makes the assumption that an instance of T can be created by invoking a parameterless constructor, might as well enforce it.

To reiterate, maybe there's some reason in the rest of your code why ListBase needs to be generic, but as far as I can see from this code, you're only unnecessarily complicating things by doing so. Making it non-generic would solve pretty much all of your problems.

edit;
Another thing:
code:
 if (field.FieldType.Equals(typeof(List<ICommon>)))
{
//snip
((ListBase<ICommon>) parent)
Your method of determining that parent is a ListBase is because it has a field of type List<ICommon>? Really? :stare:

dwazegek fucked around with this message at 10:32 on Nov 17, 2011

Mr. Crow
May 22, 2008

Snap City mayor for life
First off thanks for the help/comments!

dwazegek posted:

Your main problem is this line:
((ListBase<ICommon>) parent).Add(child)

[edit]
To clarify, the cast is the problem:
((ListBase<ICommon>) parent)

The Add(child) is not an issue, because your code throws an InvalidCastException before it even gets there.
[/edit]

Parent is NOT a ListBase<ICommon>, it's a ListBase<T>, that T is constrained to implement ICommon is irrelevant as ListBase<T> does not derive from ListBase<ICommon>.

Since you're using reflection to determine T, there's no really easy way to make that cast work. It can be done by some other fuckery, but that solution would probably be more at home in the coding horrors thread than here.

But, like others have already suggested, this should work:
code:
dynamic d = parent;
d.Add(child);

Well I know the cast is the problem, that was the question. Guess I was hoping for to much as far as constraints are concerned and being able to cast; hadn't thought of dynamic though so thanks.

quote:

Couple of other things:

code:
public abstract ListBase<T> : SUPERBASEWHATSUP where T : ICommon
{
  private List<ICommon> list;
 
  public void Add(ICommon item)
  {
    if (item != null)
      list.Add(item)
  }
}
Why is ListBase a generic if you're allowing any type of ICommon? Shouldn't it be like this?

code:
public abstract ListBase<T> : SUPERBASEWHATSUP where T : ICommon
{
  private List<T> list;
 
  public void Add(T item)
  {
    if (item != null)
      list.Add(item)
  }
}
Or you could simply remove the generic argument from ListBase and solve your casting problem, as well as the problems of determining what T is in the first place.

It originally wasn't generic and I recently made it such because I was hoping it would make determining what the items in the list should be significantly easier than just having gigantic if/else blocks everywhere. And as I've said before, the List is <ICommon> instead of <T> to account for the data that we need to keep track of that is completely foreign or otherwise wrong.

quote:

code:
SUPERBASEWHATSUP child = (SUPERBASEWHATSUP) Activator.CreateInstance(listType[0]);
Why do you have a constraint of ICommon on ListBase<T> when your code always assumes it's a SUPERBASEWHATSUP? Either T should be constrained to SUPERBASEWHATSUP or this should be a cast to ICommon.

Also, if you really need to keep ListBase<T>'s generic parameter, consider adding new() to ListBase<T>'s constraint. Your code already makes the assumption that an instance of T can be created by invoking a parameterless constructor, might as well enforce it.

To reiterate, maybe there's some reason in the rest of your code why ListBase needs to be generic, but as far as I can see from this code, you're only unnecessarily complicating things by doing so. Making it non-generic would solve pretty much all of your problems.

Well like I said it originally was. And the ICommon / SUPERBASEWHATSUP thing, ICommon is the version independent representation of a node, SUPERBASEWHATSUP is the most basic representation of a node for a given version. They release a new version of the standard every couple years and the idea is to support every version going forward, rather than just the latest.

quote:

edit;
Another thing:
code:
 if (field.FieldType.Equals(typeof(List<ICommon>)))
{
//snip
((ListBase<ICommon>) parent)
Your method of determining that parent is a ListBase is because it has a field of type List<ICommon>? Really? :stare:

Same problem as above, can't exactly do is ListBast<ICommon> (which I should :colbert:). It's not pretty but either I can have a huge gently caress-off if-statement with every T (of which there are at minimum 30) which I'd have to remember to change if anything else was changed, or I can just key off the field they will all have in common, and only lists have in common.

Although I think I've had an epiphany on how to make the whole situation less annoying/terrible and still be able to handle the unknown/incorrect data.

Mr. Crow fucked around with this message at 18:16 on Nov 17, 2011

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

Mr. Crow posted:

...

Can't you just add HasChildren and GetChildren functions to you ICommon interface (or to your base class)? Then your whole GetChildren function could be changed to a simple recursive iterator function:
code:
private static IEnumerable<ICommon> GetChildren(ICommon parent)
{
  foreach (ICommon child in parent.GetChildren())
  { 
    yield return child;
    if (child.HasChildren)
    {
      foreach (ICommon grandChild in GetChildren(child))
      {
        yield return grandChild;
      }
    }    
  }
}
By adding a couple of properties that allow you to ask an ICommon what kind of data type it is and how it should be treated, you could end up with a much clearer design.


In the case of ListBase<T>, like you've seen, working with generics has the disadvantage that you lose an easily workable base class. You can solve this by inserting a non-generic subclass (adding an interface would work as well).
code:
public abstract class ListBase : SUPERBASEWHATSUP
public abstract class ListBase<T> : ListBase where T : ICommon
Then your cast would have simply been ((ListBase)parent).Add(child).

Mr. Crow
May 22, 2008

Snap City mayor for life

dwazegek posted:

Can't you just add HasChildren and GetChildren functions to you ICommon interface (or to your base class)? Then your whole GetChildren function could be changed to a simple recursive iterator function:
code:
private static IEnumerable<ICommon> GetChildren(ICommon parent)
{
  foreach (ICommon child in parent.GetChildren())
  { 
    yield return child;
    if (child.HasChildren)
    {
      foreach (ICommon grandChild in GetChildren(child))
      {
        yield return grandChild;
      }
    }    
  }
}
By adding a couple of properties that allow you to ask an ICommon what kind of data type it is and how it should be treated, you could end up with a much clearer design.

ICommon does actually have a GetChildren method (returns an empty list if there are no concrete children), this GetChildren function is part of a completely separate thing (and in this context is probably misleading). It's basically a rough and ready temporary internal editor I'm making for these files because we need to be able to create "template files" that in the normal business side we would just read in a template file, and then pulling a bunch of crap from the DB update the file as necessary.

quote:

In the case of ListBase<T>, like you've seen, working with generics has the disadvantage that you lose an easily workable base class. You can solve this by inserting a non-generic subclass (adding an interface would work as well).
code:
public abstract class ListBase : SUPERBASEWHATSUP
public abstract class ListBase<T> : ListBase where T : ICommon
Then your cast would have simply been ((ListBase)parent).Add(child).

Yea I'm not sure why I didn't just do that to begin with and it's what I ended up doing (among other things). I think I didn't completely understand generics (well I still don't) and thought it would be an unnecessary layer when I could just as easily call is Parent<> or something.

Mr. Crow fucked around with this message at 19:15 on Nov 17, 2011

genki
Nov 12, 2003

Mr. Crow posted:

Yea I'm not sure why I didn't just do that to begin with and it's what I ended up doing (among other things). I think I didn't completely understand generics (well I still don't) and thought it would be an unnecessary layer when I could just as easily call is Parent<> or something.
It's possible to make the Parent<> call, but if you don't have to, then don't do it. I'll try to look it up later for reference, but the superbase solution is much better to use.

Adbot
ADBOT LOVES YOU

Mr. Crow
May 22, 2008

Snap City mayor for life
I had found it earlier on SO, I assume this is what you mean?

code:
if (myVar.GetType().IsGenericType
 && myVar.GetType().GetGenericTypeDefinition() == typeof(BaseClass<>))
Or in my case calling that on the GetType().BaseType.

  • Locked thread