Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 委托vs接口与DI的单一方法_C#_.net_Interface_Dependency Injection_Delegates - Fatal编程技术网

C# 委托vs接口与DI的单一方法

C# 委托vs接口与DI的单一方法,c#,.net,interface,dependency-injection,delegates,C#,.net,Interface,Dependency Injection,Delegates,我有一项任务要做一些背景工作。我想注入voidthrottle(taskState)方法。为了调试的目的,它可以像Thread.Sleep(delay)一样简单,但也可以更复杂,比如做一些日志记录等等 我在委托和带有单个方法的接口之间进行选择,作为任务驱动类构造函数的参数选择哪个选项? 在我看来,当涉及到DI时,接口相对于委托的主要优势是可扩展性。可以很容易地添加新方法。我可以创建接口I2:I1{…},让类实现I2,并且仍然以I1的形式注入它的实例。客户端代码有一个选项可以将其强制转换为I2,以

我有一项任务要做一些背景工作。我想注入
voidthrottle(taskState)
方法。为了调试的目的,它可以像
Thread.Sleep(delay)
一样简单,但也可以更复杂,比如做一些日志记录等等

我在委托和带有单个方法的接口之间进行选择,作为任务驱动类构造函数的参数选择哪个选项?

在我看来,当涉及到DI时,接口相对于委托的主要优势是可扩展性。可以很容易地添加新方法。我可以创建
接口I2:I1{…}
,让类实现
I2
,并且仍然以
I1
的形式注入它的实例。客户端代码有一个选项可以将其强制转换为
I2
,以查看是否支持新功能

然而,如果我只需要注入一个方法,我认为委托会更有意义,不管我是否需要维护状态。学员也可以保持状态,例如:

static Action<TaskState> GetThrottle(int delay) 
{ 
    return (s) => Thread.Sleep(delay++);
} 
静态动作GetThrottle(int延迟)
{ 
返回=>Thread.Sleep(延迟++);
} 
我会显式地键入我的委托,而不是使用
Action
Func

目前,我计划有一个单独的
static
类,包含上述各种
Throttle
实现

我没有在这个项目中使用任何DI框架

这是正确的选择吗?我应该改用界面吗


如果你认为答案大部分是基于意见的,那么投票结束这个问题也会有帮助。

在他的一次演讲中,智者大卫·查佩尔曾经说过,如果你面临一个设计问题,有几种方法可以解决它,您必须在快捷方式和提供可扩展性的有点困难的路径之间做出选择,选择后者。如果将来需要,扩展性可能会派上用场。如果你在晚上开车,当你的前灯到达时,你只能看到很远的地方。随着你们的前进,道路变得越来越清晰。虽然这可能不适用于所有可能的情况,但这个建议对我帮助很大


在你的情况下,如果我不确定一个委托是我所需要的全部,我会通过使用接口使其可扩展。

在他的一次演讲中,智者David Chappell曾说过,如果你面临的设计问题有两种方法可以解决,您必须在快捷方式和提供可扩展性的有点困难的路径之间做出选择,选择后者。如果将来需要,扩展性可能会派上用场。如果你在晚上开车,当你的前灯到达时,你只能看到很远的地方。随着你们的前进,道路变得越来越清晰。虽然这可能不适用于所有可能的情况,但这个建议对我帮助很大


在您的情况下,如果我不确定一个委托是我所需要的全部,我会通过使用接口使其可扩展。

将接口传递给构造函数的一个优点是它使依赖项解析更容易在DI框架中声明。如果你有一个像这样的班级

public class ClassA{
    public ClassA(IInterface interface){
    ...
    }
}
然后使用像Unity这样的DI框架,我可以很容易地注册这样的类型

 container.RegisterType<IInterface, ConcreteImplementation>();
那么,注册依赖项就有点难了

 container.RegisterType<ClassA>(
     new InjectionFactory(a => {
         return new ClassA(()=>{/*delegate code*/});
 }));
container.RegisterType(
新注射工厂(a=>{
返回新的ClassA(()=>{/*委托代码*/});
}));

将接口传递给构造函数的一个优点是,它使依赖项解析更容易在DI框架中声明。如果你有一个像这样的班级

public class ClassA{
    public ClassA(IInterface interface){
    ...
    }
}
然后使用像Unity这样的DI框架,我可以很容易地注册这样的类型

 container.RegisterType<IInterface, ConcreteImplementation>();
那么,注册依赖项就有点难了

 container.RegisterType<ClassA>(
     new InjectionFactory(a => {
         return new ClassA(()=>{/*delegate code*/});
 }));
container.RegisterType(
新注射工厂(a=>{
返回新的ClassA(()=>{/*委托代码*/});
}));

向接口添加额外方法的能力是一把双刃剑。几个类依赖于一个接口。一个类需要一些额外的依赖项,有人决定将其放入现有接口(及其实现)中。他们不应该这样做,但他们确实这样做了。现在,依赖项有一个其他类不需要的额外方法,因此违反了接口隔离。另外,依赖它的类正在做更多的事情,但很难判断,因为它的依赖项数量没有增加

您可以使用DI容器注册代理。一开始并不漂亮,但有一些扩展方法就可以了。在某些情况下,静态方法是合适的,将静态方法注册为委托的实现非常容易,因为没有要注册或解析的类型,只有委托本身

以下是使用Autofac的示例:

代表:

public delegate Single DoMath(Single value1, Single value2);
分机:

public static class AutofacBuilderExtensions 
{ 
    public static IRegistrationBuilder<TDelegate, SimpleActivatorData, SingleRegistrationStyle> RegisterDelegate<TDelegate, TSource>( 
        this ContainerBuilder builder,  
        Func<TSource, TDelegate> extractDelegate,  
        string sourceComponentName = null,  
        string registeredComponentName = null)  
        where TDelegate : class
    {
        var registrationFunction = new Func<IComponentContext, TDelegate>(context => 
        { 
            var c = context.Resolve<IComponentContext>(); 
            var source = sourceComponentName == null 
                ? c.Resolve<TSource>() 
                : c.ResolveNamed<TSource>(sourceComponentName); 
            return extractDelegate(source); 
        }); 

        return registeredComponentName == null ? 
            builder.Register(registrationFunction) : 
            builder.Register(registrationFunction) 
                .Named<TDelegate>(registeredComponentName); 
    } 
}

// register the type containing the method so it can be resolved,
// and then register the implementation of the delegate using the extension.
builder.RegisterType<AddsNumbers>();
builder.RegisterDelegate<DoMath, AddsNumbers>(addsNumbers => addsNumbers.DoMath);
公共静态类AutofacBuilderExtensions
{ 
公共静态iRegistrationBuilderRegisterDelegate(
这个集装箱建造商,
Func代表,
字符串sourceComponentName=null,
字符串registeredComponentName=null)
TDelegate:类在哪里
{
变量注册函数=新函数(上下文=>
{ 
var c=context.Resolve();
var source=sourceComponentName==null
?c.解决()
:c.ResolveNamed(sourceComponentName);
返回代理(源);
}); 
返回registeredComponentName==null?
生成器注册(注册功能):
生成器注册(注册功能)
.Named(registeredComponentName);
} 
}
//注册包含该方法的类型,以便对其进行解析,
//然后使用扩展注册委托的实现。

RegisterType

向接口添加额外方法的能力