NightOwl888 commented on issue #1059:
URL: https://github.com/apache/lucenenet/issues/1059#issuecomment-2543953460

   > > It looks like you neatly solved access to the GroupCount field using 
IGroupCountCollector, but the tests don't access the Groups property so there 
is no need to find a solution to cast it AFAICT.
   > 
   > I actually already removed that in lieu of having this do the same 
approach as the other collectors in the tests, so that we're not adding an 
unnecessary interface just for testing purposes. It's unlikely that someone 
would need just the group counts in the real world without also accessing the 
groups, so I figured it would be best to not pollute the public API with that 
interface when it was only used (read: not needed, just used as one approach) 
for test purposes.
   
   -----------------
   
   > I just had an idea, based on that last comment, if you're open to it. We 
could create non-generic interfaces (not abstract classes) that do not expose 
collections, but give you APIs to retrieve items. By using an interface instead 
of an abstract class, we wouldn't be forced to convert to/from object except 
for in the explicitly implemented methods. It also would not change the type 
hierarchy. For example:
   > 
   > ```cs
   > public interface IAllGroupsCollector : ICollector // NOTE: we'd need to 
keep this interface
   > {
   >     int GroupCount { get; }
   >     object GetGroup(int index);
   > }
   > ```
   > 
   > We would then explicitly implement the interface for the GetGroup method. 
I think that would be cleaner than exposing a non-generic ICollection, although 
I could be swayed on explicitly implementing that too. Thoughts?
   
   That is the reason why I said "abstraction" rather than "abstract class", 
because either would probably be fine. I just used abstract classes in most 
other places because it meant keeping the same syntax as the upstream code. For 
example:
   
   #### Java
   
   ```java
   List<AbstractAllGroupsCollector> collectors = new ArrayList();
   ValueSource vs = new BytesRefFieldSource(groupField);
   collectors.add(new FunctionAllGroupHeadsCollector(vs, new Map(), 
sortWithinGroup));
   collectors.add(TermAllGroupHeadsCollector.Create(groupField, 
sortWithinGroup));
   ```
   
   #### C#
   
   ```c#
   List<AbstractAllGroupsCollector> collectors = new 
List<AbstractAllGroupsCollector>();
   ValueSource vs = new BytesRefFieldSource(groupField);
   collectors.Add(new FunctionAllGroupHeadsCollector(vs, new Hashtable(), 
sortWithinGroup));
   collectors.Add(TermAllGroupHeadsCollector.Create(groupField, 
sortWithinGroup));
   ```
   
   Where if we used an interface, it would be declared a bit different:
   
   ```c#
   List<IAllGroupsCollector> collectors = new List<IAllGroupsCollector>();
   ```
   
   The main reason for doing this in other places was for being able to access 
constants and fields without having to specify the non-generic type (in which 
case the syntax stays the same as upstream).
   
   It would also allow the use of the `Collector` abstract class, so the user 
could cast to that type just as they could in Java. Being that there are no 
methods on `ICollector` that wouldn't also exist on `Collector`, that is not 
such a big deal, though.
   
   That being said, using an interface does have an advantage we may be able to 
take advantage of: it can be declared internal and used just for testing 
purposes. If we use an abstract class, it will have to be declared public in 
order for a public type to inherit it. Although, I am not entirely convinced 
that getting the `GroupCount` without having strongly-typed access to the 
groups is not a valid use case.
   
   After mulling this over a bit more, if the user needed to create a 
collection of mixed collectors, they could just declare it `object` or 
`ICollector` and then pass it through a set of cast tests upon usage. However, 
they would need to know all possible types that it could be cast to at compile 
time, which might not be possible for every use case.
   
   ```c#
   //List<AbstractGroupingSearch> collectors = new 
List<AbstractGroupingSearch>();
   List<object> collectors = new List<object>();
   
   collectors.Add(GroupingSearch.ByField(...));
   collectors.Add(GroupingSearch.ByFunction<MutableValueStr>(...));
   collectors.Add(GroupingSearch.ByFunction<MutableValueInt32>(...));
   collectors.Add(GroupingSearch.ByDocBlock<string>(...));
   collectors.Add(GroupingSearch.ByDocBlock<int>(...));
   
   foreach (object collector in collectors)
   {
       if (collector is FieldGroupingSearch fieldGroupingSearch)
           // do something with the collector
       else if (collector is FunctionGroupingSearch<MutableValueStr> 
functionOnString)
           // do something with the collector
       else if (collector is FunctionGroupingSearch<MutableValueInt32> 
functionOnInt32)
           // do something with the collector
       else if (collector is DocBlockGroupingSearch<string> docBlockOnString)
           // do something with the collector
       else if (collector is DocBlockGroupingSearch<int> docBlockOnInt32)
            // do something with the collector
   }
   ```
   
   This would be very cumbersome if all they want to do is read a field that is 
common among all of these types and even moreso if they wanted to do that for 
any custom subclass (which would probably require reflection).
   
   I am not opposed to keeping `ICollector`. The only thing that is kind of 
smelly about it is that there is one constant that is declared on `Collector` 
because interfaces in c# don't support constants. So, we need the `Collector` 
class whether it is made abstract or not. Since it is currently a static class, 
users could be confused that they cannot cast a collector type to `Collector` 
as is the case in Java.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscr...@lucenenet.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to