Grasshopper

algorithmic modeling for Rhino

List of Unknown classes that implement common interface - but need to contain list(s)

So imagine the following schema, abstracted for (I hope) clarity and simplicity. I tried three approaches to get it to work, but none seem to do the trick. Is there a programming concept that would get around this? Can anyone give me some insight on implementation?

Custom class

Ingredient

Custom interface

IFood

Method: bake

Method: eat

Custom class A

Pizza : IFood

simple (eg. string or int) properties are set in constructor

bake() and eat() are defined in the class, as one would expect

List<Ingredient> myIngredients;

Custom class B

Lasagna : IFood

simple (eg. string or int) properties are set in constructor

bake() and eat() are defined in the class, as one would expect

List<Ingredient> myIngredients;

The trouble comes when I try to do something like this:

Grasshopper component : "Recipe"

Should accept either custom class A or custom class B, and be able to loop through their ingredients and output a long string.

Method 1:

Recipe component accepts and performs operations on objects of type "IFood", but gives an error because "IFood" does not contain a definition for "myIngredients".

Method 2 (I think this is the right path):

Try adding "List<Ingredient> myIngredients" to "IFood" and get two errors "Interfaces cannot contain fields" and "Inconsistent accessibility: field type 'List<Ingredient>' is less accessible than field 'IFood.myIngredients' "

Method 3:

Try adding a method to "IFood" called "myIngredients". This would be defined in each class that implements the interface and return all the ingredients as a list. Errors: "Inconsistent accessibility: return type 'Ingredient' is less accessible than method 'IFood.myIngredients()' " Also a bunch of errors in the "Recipe" component, where I try to actually use IFood.myIngredients... 

Views: 260

Replies to This Discussion

Method 2 is indeed the right approach. You should never expose fields anyway, add a readonly property to IFood which returns an ingredient collection:

IEnumerable<Ingredient> Ingredients { get; } 

You can use List<Ingredient> or Ingredient[] as well of course, I just like to use IEnumerable and implement it as a yield property:

public IEnumerable<Ingredient> Ingredients{

get

{

  foreach (Ingredient ingredient in _ingredients)

    yield return ingredient;

}

}

This approach prevents callers from changing the ingredient collection without the need to duplicate the collection each time it is accessed.

Incidentally if Ingredient is less accessible than the IFood interface (for example if IFood is public, but Ingredient is internal), then my solution won't work. You'll either have to elevate the accessor of Ingredient to be identical to or higher than IFood, or you need to create a second interface (let's say IIngredientList) which has the same access level. Your components will then need to use this second interface to access the ingredients.

Thanks!

I added a public keyword to Ingredient, and that cleared up the accessor issue, a totally newbie mistake on my part.

I ended up implementing Ingredients as an IList, so I can add additional ingredients, even after initial construction of the class.

If anyone else finds this and is wondering how to do IList, this article is really helpful:

http://stackoverflow.com/questions/4458900/why-it-is-not-possible-t...

Thanks again for your help David!

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service