Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.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# 使用Func<&燃气轮机;通过接口?_C#_Design Patterns_Interface_Func_Solid Principles - Fatal编程技术网

C# 使用Func<&燃气轮机;通过接口?

C# 使用Func<&燃气轮机;通过接口?,c#,design-patterns,interface,func,solid-principles,C#,Design Patterns,Interface,Func,Solid Principles,我有一个已经存在的泛型类 public class Foo<T> { private T _item; public Foo(T item){ _item = item;} } 公共类Foo { 私人信托基金项目; 公共Foo(T项){u项=项;} } 我必须创建一个方法,该方法将返回T的某个属性。 我在这里看到两种解决方案 创建接口: public const string TestVar = "bar"; public interface INamable {

我有一个已经存在的泛型类

public class Foo<T>
{
    private T _item;
    public Foo(T item){ _item = item;}
}
公共类Foo
{
私人信托基金项目;
公共Foo(T项){u项=项;}
}
我必须创建一个方法,该方法将返回T的某个属性。
我在这里看到两种解决方案

  • 创建接口:

    public const string TestVar = "bar";
    public interface INamable { string Name { get; } }
    public class Bar : INamable
    {
        public string Name { get { return TestVar; } }
    }
    
    public class Foo<T> where T : INamable
    {
        private T _item;
        public Foo(T item) { _item = item; }
        public string GetName() { return this._item.Name; }
    }
    
    [TestMethod()]
    public void TestInterface()
    {
        var bar = new Bar();
        var foo = new Foo<Bar>(bar);
        Assert.AreEqual(TestVar, foo.GetName());
    }
    
    公共常量字符串TestVar=“bar”; 公共接口不可命名{string Name{get;}} 公共类酒吧:无法使用 { 公共字符串名称{get{return TestVar;}} } 公共类Foo,其中T:INamable { 私人信托基金项目; 公共Foo(T项){u项=项;} 公共字符串GetName(){返回此。\u item.Name;} } [TestMethod()] 公共无效测试接口() { var bar=新的bar(); var foo=新foo(bar); AreEqual(TestVar,foo.GetName()); }
  • 传递函数:

    public const string TestVar = "bar";
    public class Bar
    {
        public string Name { get { return TestVar; } }
    }
    
    public class Foo<T>
    {
        private T _item;
        private Func<T, string> _funcName;
        public Foo(T item, Func<T, string> funcName) { _item = item; _funcName = funcName; }
        public string GetName() { return _funcName.Invoke(_item); }
    }
    
    [TestMethod()]
    public void TestFunc()
    {
        var bar = new Bar();
        var foo = new Foo<Bar>(bar, b => b.Name);
        Assert.AreEqual(TestVar, foo.GetName());
    }
    
    公共常量字符串TestVar=“bar”; 公共类酒吧 { 公共字符串名称{get{return TestVar;}} } 公开课Foo { 私人信托基金项目; 私有函数_funcName; public Foo(T item,Func funcName){{u item=item;\u funcName=funcName;} 公共字符串GetName(){return _funcName.Invoke(_item);} } [TestMethod()] public void TestFunc() { var bar=新的bar(); var foo=新foo(bar,b=>b.Name); AreEqual(TestVar,foo.GetName()); }
  • 我使用第二种解决方案,因为我不必创建接口,而且我很懒。只需向foo构造函数的已调用添加一个参数

    此外,Foo类仍然可以用于所有类型的类,我更喜欢这种方式

    但是,我不确定这是否是使用Func的好方法?它仍然是好的和坚实的吗?这是我第一次尝试使用Func,这就是为什么我问自己


    几个月前,我使用了第一个解决方案,使用了经典的界面…

    第一个解决方案(即没有Func)要简单得多。完全不需要调用Func对象来实现各种各样的属性访问器。

    如果您的接口最终只有一个方法,那么使用
    操作
    Func
    委托是完全有效的。我觉得那更干净


    不过,您不必编写
    调用
    。用括号来称呼它:
    \u funcName(\u item)

    我在重新措辞我的答案,因为从评论中我意识到我不是很清楚

    这取决于代码的意图以及谁有责任为类命名(客户机应该知道并指定如何命名类,而类本身应该有名称)。我对@Scorpi0的例子做了一点修改,这样Foo就可以用这个名字做一些事情(它向它打招呼),而不仅仅是返回它

    示例1(接口)
    接口不可配置{string Name{get;}
    与名称相关的类别:不可复制
    {
    公共字符串名称{get{return“thing”;}
    }
    另一类与名称有关的内容:不可复制
    {
    公共字符串名称{get{返回“不同的东西”;}
    }
    类Foo,其中T:INamable
    {
    公共字符串问候语(T项){返回“hi”+项;}
    }
    
    这里的东西都有一个名字,不考虑Foo。Foo知道如何打招呼,只要他们有一个名字(这是由他们实现INamable接口的合同保证的)。 在这里,您希望保证Foo只对具有名称的事物起作用,并且尝试对其他事物表示欢迎应该是编译器捕获的类型错误

    另外,请注意,您正在每个类中封装Name的具体实现。名称可能取决于其类的私有状态

    示例2(Func)
    classathing{}
    类另一个未更新项{}
    福班
    {
    公共字符串问候语(T项,函数命名函数)
    {
    返回“hi”+命名功能(项目);
    }
    }
    
    这里的重点是Foo。事物不一定有名字。我想建立一个可以迎接任何事情的类Foo。它是怎么做到的?对于任何类型,调用方都有责任传入一个可以为该类型命名的函数。 在这种情况下,我们不仅没有要求保证T知道它自己的名称,而且我们正在以一种方式构建Foo,只要我们知道如何给它命名,它就可以迎接任何类型。例如,这项工作:

    var foo = new Foo<int>();
    var res=foo.Greet(2, n=>n.ToString());
    
    var foo=new foo();
    var res=foo.Greet(2,n=>n.ToString());
    
    作为这种灵活性的交换,我们放弃了封装。现在名称不再是类的责任来实现,我们(调用方)正在告诉Foo如何为使用它的每个类命名


    因此,根据您想要表达的内容,如果您有一个具有名称的对象层次结构,而不考虑Foo,您可以选择一种或另一种方式。

    在许多情况下,委托对于实现者来说会更方便,因为vb.net和C#编译器都包含使其使用非常方便的功能。接口可以做一些委托不能做的事情(例如,包括开放泛型方法族),并且在某些情况下可能比委托更有效(因为对实现接口的对象的引用可以作为该接口类型传递,而无需创建另一个堆对象来保存它)。然而,编译器支持轻松创建内联委托,虽然没有为单函数接口提供类似的功能,但这一事实为前者提供了一个非常有力的论据。

    尝试勾勒出将使用此方法的代码(客户端代码):哪种方法更适合使用?另外,如果您试图访问的属性/字段不是公共的,该怎么办?创建另一个类型比使用已有类型更简单吗?嗯?这与接口方法有何不同?客户端还可以以一种完全不涉及Name属性的方式实现接口。我假设
    Foo
    INamable
    在库代码中。现在,客户端必须创建一个
    ,该条实现
    不可编辑
    ,以便使用
    class AThing {}
    class AnotherUnrelatedThing {}
    
    class Foo<T>
    {
        public string Greet(T item, Func<T, string> namingFunction) 
        {
            return "hi " + namingFunction(item);
        }
    }
    
    var foo = new Foo<int>();
    var res=foo.Greet(2, n=>n.ToString());