C# Best Practice: Using a delegate or an interface as a class dependency
Asked Answered
I

4

8

I have a class that requires a way to retrieve a random integer value with a maximum. I don't want this class to depend on a specific way to retrieve that random value (such as system.random). Would it be best to:

(A) Use a public delegate (or func)

public delegate int NextRandomInt(int maxValue);

public class MyClass
{
    public NextRandomInt NextRandomInt { get; set; }

    public MyClass(NextRandomInt nextRandomInt)
    {
        NextRandomInt = nextRandomInt;
    }
}

(B) Use a public interface

public interface IRandomIntProvider
{
    int NextInt(int maxValue);
}

public class MyClass
{
    public IRandomIntProvider RandomIntProvider { get; set; }

    public MyClass(IRandomIntProvider randomIntProvider)
    {
        RandomIntProvider = randomIntProvider;
    }
}

(C) Something else all together.

Both ways work. I feel like using a delegate would be simpler and quicker to implement, but the interface is more readable and may be easier when dependency injection comes around.

Inseminate answered 14/4, 2016 at 15:0 Comment(1)
Check for Strategy GOF design pattern. It may help you.Syllabi
Q
2

It's slightly hair-splitting, since either an interface or a delegate will work.

One reason to prefer the delegate in this case is that you're really only depending on a method, so it's a tiny bit redundant to have to declare both the interface and the method. If your process is anything like mine, the method name was obvious but the interface name wasn't, because it doesn't really mean anything. It's a container for the method. (And I would have ended up with almost the exact same name as you did.)

Also, a delegate gives you the option to use a static method. Your class still depends on an abstraction, so you can pass in a mocked method if needed for unit testing the class. I'm not usually a big fan of static methods, but that's largely because they interfere with testability. But if you're depending on a delegate rather than directly on the function then it doesn't matter.

Quail answered 26/3, 2018 at 19:8 Comment(0)
F
1

It depends as to how much job you want to implement using a delegate or an interface.

If your interface is going to have only one or even two methods, you could use a Func to force the same behavior. Otherwise i would use interfaces.

Mark Seemann explained just this pretty nicely here : link

To sum it up he states this:

Whenever possible, I prefer to model my APIs with delegates instead of one-method interfaces, since it gives me greater flexibility and less infrastructure code.

Obviously, this technique only works as long as you only need to abstract a single method. As soon as your abstraction needs a second method, you will need to introduce a proper interface or, preferably, an abstract base class.

Floatage answered 14/4, 2016 at 15:9 Comment(0)
P
0

To my point of view (I am sure) the second option with interface is the best. This situation is a typical example of the Strategy pattern.

Puett answered 14/4, 2016 at 15:2 Comment(2)
Why is an interface best in your opinion? And how are these two statements related? Strategy can be implemented with all kinds of abstractions, including delegates, so I don't see how Strategy implies the use of an interface.Zanazander
@Mr.Putty I wrote that it is my point of view :) I prefer interfaces in such examples because for using delegate you should create a method in some class (and I don't see how this class should be named - RandomDelegates?). And it just will be more beautiful to create a little interface with specific class. I hope I could explain my idea.Puett
H
0
  1. Use Interface if you think that there may be another implementation of NextRandomInt() may exist in the system.
  2. Choose delegate if you think it shall be executed as a cause of an event or callback.
    Otherwise simply go with a method as class member. It's up to you if you want the method to be available as instance method or static.
Hallowmas answered 14/4, 2016 at 15:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.