接口泛型实现

时间:2016-08-19 13:21:45

标签: c# generics

我有以下界面:

public interface ISapFunction
  {
    void Import<T>(T obj);
    T Export<T>();
    void Call(RfcRepository repo, RfcDestination dest);
  }

然后我尝试按如下方式实现它:

public class SapMaterialFormatter : ISapFunction
  {
    private static SapMaterialFormatter _self;
    private string _formatted;
    private string _raw;

    private SapMaterialFormatter()
    {
    }

    public void Import<string>(string obj)
    {
     _raw = obj;
    }

    public string Export<string>()
    {
      return _formatted;
    }

    public void Call(RfcRepository repo, RfcDestination dest)
    {
      var bapi = repo.CreateFunction("FUNCTION");
      bapi.SetValue("IF_INPUT", _raw);
      bapi.Invoke(dest);
      _formatted = bapi.GetString("EF_OUTPUT");
    }

    public static SapMaterialFormatter Factory()
    {
      return _self ?? new SapMaterialFormatter();
    }
  }

但编译器抱怨,生成语法错误:

enter image description here

实施有什么问题?

5 个答案:

答案 0 :(得分:7)

它们是通用方法参数,因此在调用这些接口方法时需要提供它们。

例如:impl.Import<string>(...)

您的实现应该只定义整个T通用参数:

public void Import<T>(T obj)
{

}

如果您想获得所需的效果,则需要定义泛型类型参数T并删除其方法范围的对应项:

public interface ISapFunction<T>
  {
    void Import(T obj);
    T Export();
    void Call(RfcRepository repo, RfcDestination dest);
  }

答案 1 :(得分:2)

实施是实施开放式通用方法Import<T>Export<T>所必需的,而不是封闭的通用方法,例如Import<string>Export<string>

实现类不指定T,而是调用方法的调用站点。

示例:

var sapFunction = ...;
sapFunction.Import<string>(...);

如果您确实希望实现类指定类型,您可以在界面中声明它,如下所示:

public interface ISapFunction <T>
  {
    ..
  }

然后实施它:

public class SapMaterialFormatter : ISapFunction<string>

答案 2 :(得分:2)

您的界面声明了泛型方法,因此您的实现也必须是通用的:

public class SapMaterialFormatter : ISapFunction
{
    // shortened for brevity

    public void Import<T>(T obj)
    {
         _raw = obj;
    }

    public T Export<T>()
    {
         return _formatted;
    }

    public void Call(RfcRepository repo, RfcDestination dest)
    {
    }
}

如果要创建具有特定类型的派生类,您可能想要声明您的界面:

public interface ISapFunction<T> // declare generic parameter here
{
    void Import(T obj); // but not here
    T Export();
    void Call(RfcRepository repo, RfcDestination dest);
}

然后宣布您的班级实施ISapFunction<string>

public class SapMaterialFormatter : ISapFunction<string>
{
    // shortened for brevity

    public void Import(string obj)
    {
         _raw = obj;
    }

    public string Export()
    {
         return _formatted;
    }

    public void Call(RfcRepository repo, RfcDestination dest)
    {
    }
}

答案 3 :(得分:0)

您可以选择两种不同的方法来实现接口中方法的通用参数:

解决方案1。

public interface ISapFunction
{
    void Import<T>(T obj);
    T Export<T>();
}

public class SapMaterialFormatter : ISapFunction
{
    private static SapMaterialFormatter _self;
    private string _formatted;
    private string _raw;

    public static SapMaterialFormatter Factory()
    {
        return _self ?? new SapMaterialFormatter();
    }

    public void Import<T>(T obj)
    {
        throw new NotImplementedException();
    }

    public T Export<T>()
    {
        throw new NotImplementedException();
    }
}

它包括在接口和实现类中将方法定义为泛型,它可以像这样使用:

var sap = new SapMaterialFormatter();
sap.Export<string>();

解决方案2。

public interface ISapFunction<T>
{
    void Import(T obj);
    T Export();
}

public class SapMaterialFormatter : ISapFunction<string>
{
    private static SapMaterialFormatter _self;
    private string _formatted;
    private string _raw;

    public static SapMaterialFormatter Factory()
    {
        return _self ?? new SapMaterialFormatter();
    }

    public void Import(string obj)
    {
        throw new NotImplementedException();
    }

    public string Export()
    {
        throw new NotImplementedException();
    }
}

其中包括将接口声明为接受泛型并在方法中使用它。

然后您可以将其用作:

var sap = new SapMaterialFormatter();
sap.Export();

注意:我已经删除了方法的内容以确保代码编译,您可以随意更改样本。

答案 4 :(得分:0)

正如大家已经向您解释过的那样,您必须使您的实现变得通用,您无法指定类型。

主要原因是,如果我做这样的事情:

interface ISomething
{
    T Method<T>();
}

class SomethingWithString : ISomething
{
    public string Method<string>()
    {
        return "Hello World !";
    }
}

class SomethingWithInt : ISomething
{
    public int Method<int>()
    {
        return 42;
    }
}

根据您的说法,SomethingWithStringSomethingWithInt都会实施ISomething

所以我可以写:

IEnumerable<ISomething> enumerable = new ISomething[]
{
    new SomethingWithString(),
    new SomethingWithInt()
};

在这里:

IEnumerable<?> results = enumerable.Select(x => x.Method()); // We may have a problem here...

除了使用对象/动态类型,我们无法知道Method返回的类型。

这就是为什么你必须改变你的实施,其他答案已经告诉你如何做到这一点。