Implementing objects with internal constructors

Recently i created a bug in the Libraries repo finding the need to change Event Arg constructor from internal to public, in order to implementing an interface.

Basically the problem is GpioPinValueChangedEventArgs internal constructor prevents me from creating the object when attempting to trigger the event.

Quick search suggests no explicit way to do this, but perhaps im missing something and someone might be able to advise me of it.

Access Modifiers - C# Reference | Microsoft Docs

interface - C# Reference | Microsoft Docs

I am going to try to see if I can provide some insight based on my understanding, I am making some assumptions here. You mention interface having an affect on your internal constructor.

So here is my unsolicited input:

Interface - An interface has no bearing on how a class implements its constructor(s), it is just a contract for what the class should posses, that is, members, events, and/or the methods, not the constructors; this is different than an abstract class.

Internal - This is a modifier that sets the visibility of a class in an assembly to be instantiable only within that assembly

public delegate void SampleGpioPinValueChangedEventHandler(object sender, EventArgs e);
//Sample interface
    public interface ISample
    {
        public string Property { get; }
        public void Method();
        public event SampleGpioPinValueChangedEventHandler SampleEvent; //Must be a delegate
    }

//valid - default constructor (public)
 public class SampleClass : ISample
    {
        public string Property => throw new NotImplementedException();

        public event SampleGpioPinValueChangedEventHandler SampleEvent;
        public void Method()
        {
            throw new NotImplementedException();
        }
    }

//Valid - internal constructor, class can only be instantiated within the same assembly
 public class SampleClass : ISample
    {
internal SampleClass(){

}
        public string Property => throw new NotImplementedException();

        public event SampleGpioPinValueChangedEventHandler SampleEvent;
        public void Method()
        {
            throw new NotImplementedException();
        }
    } 

//Valid - private constructor normally used when when creating a singleton
public class SampleClass : ISample
    {
private SampleClass(){}
        public string Property => throw new NotImplementedException();

        public event SampleGpioPinValueChangedEventHandler SampleEvent;
        public void Method()
        {
            throw new NotImplementedException();
        }
    }

What you submitted on Gitub is not a bug

```
public sealed class GpioPinValueChangedEventArgs : EventArgs
  {
    public GpioPinEdge Edge { get; }

    public DateTime Timestamp { get; }

    internal GpioPinValueChangedEventArgs(GpioPinEdge edge, DateTime timestamp)
    {
      this.Edge = edge;
      this.Timestamp = timestamp;
    }
  }
```

Here, you are inheriting from a class and not an interface, in your case EventArgs. Inheritance is a topic too large to discuss in a forum.

Inheritance in C# | Microsoft Docs

Edited: The reason you had to set the constructor of your GpioPinValueChangedEventArgs class to public is because the EventArgs class has public constructor(s).

//EventArgs definition, not actual implementation
[ComVisible(true)]
    public class EventArgs
    {
        ...
        public EventArgs();
    }

First off thanks for taking the time, its often difficult to describe let alone get feedback on such issues.

Firstly to be clear, the code posted is part of the GPIO library, not my code, i wasnt sure your direction here…

But the problem is the overall implementation. In order to implement the interface member SetPinChangedHandler at some point I must trigger the event handler GpioPinValueChangedEventHandler with its required parameter
GpioPinValueChangedEventArgs. And cant do that if not able to create a GpioPinValueChangedEventArgs value because its constructor is internal.

More specifically, Im not sure how, rather i dont think it is possible, to connect the event my device is generating, to the event that the interface requires without being able to invoke it with an instantiated value of GpioPinValueChangedEventArgs

My apologies, you know the old saying “one should never assume anything”. I dig some more poking around to get a better understanding, are you trying to implement your own class based on the IGpioControllerProvider interface? I may be wrong here but I believe the GpioController may be responsible for instantiating this on your behalf when you call GpioController.FromProvider(IGpionContollerProvider yourCustomProvider). I am just trying to be of some help here.

I super appreciate it. I dont get to bounce this stuff off anyone so I hope anyone feels free to chime in.
And its always hard to convey the details when things start to get abstracted, and even harder for someone not intimately acquainted in the subject matter to then realize.

Exactly. It is my understanding implementing this interface will allow one to generate a GpioPin based on their own implementation of presumably a special implementation of say a special function for a Gpio pin, or perhaps from an eternal GPIO extender chip as im working with.

I haven’t yet figured out if this this might all be overkill or not, but the functionality to create the custom controller is there. This idea of a custom controller may make even more sense when your implementing a custom UART controller or SPI, or even I2C i guess… where functionality is more than a pin being high or low.

So from what i see one calls GpioController.FromProvider(IGpionContollerProvider yourCustomProvider) to create an implemetation of your custom GpioController. Which allows you in turn to create a framework standard GpioPin.
But the functionality of your (custom) GpioPin is defined by the interface implementation and its back end. My device will tell me (via interrupt in this case) that a pin change has happened. My library now needs to fire the underlying event dictated by the interface’s member. And to do this, from the data my device provides in its event args, the event args the interface asks for needs to be created, and that is GpioPinValueChangedEventArgs.

So in summary:

  1. My device interrupts due to a pin change
  2. i translate the devices interrupt’s args into the interrupt args needed to implement the interface, GpioPinValueChangedEventArgs and thus a value of this type needs to be created.
  3. Any subscribers to this custom GpioPin PinChange event will ultimately receive these args created in step 2.

But as long as we have internal event args constructor here, this appears to me not possible, and Im hoping to learn differently.

Here is a SO question that seems to address a similar problem.
Oddly one suggestion is to inherent from the Event Args and create my own, but for some reason TnyCLR seems to have a generous share of sealed classes, for what so far appears reasoning that escapes me.

I just noticed in the GPIO Library there is an implementation of this interface for the naitive Gpio pins.
Here we can see where the interrupt is triggered, creating the GpioPinValueChangedEventArgs just as I estimated.

Of course there is no problem as they are both in the same assembly.
Only how does any one else implement it being internal…

I ended up creating a pull request

And pull drafts demonstrating the problem

1 Like