0

I have the following interface:

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

and then I try to implement it as follows:

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(); } } 

But the compiler complains, generating syntax errors:

enter image description here

What is wrong with the implementation?

5 Answers 5

8

They're generic method parameters, so they need to be provided when you call these interface methods.

For example: impl.Import<string>(...).

Your implementation should just define the whole T generic parameter:

public void Import<T>(T obj) { } 

If you want the desired effect, you'll need to define a generic type parameter T and remove its method-scoped counterpart:

public interface ISapFunction<T> { void Import(T obj); T Export(); void Call(RfcRepository repo, RfcDestination dest); } 
Sign up to request clarification or add additional context in comments.

2 Comments

than you sould define your class as: public class SapMaterialFormatter : ISapFunction<string> {}
I think the second part of the answer is what the OP was after
2

Your interface declares a generic method, so your implementation must be generic too:

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) { } } 

If you want to create the derived class with specific types, you may have wanted to declare your interface like that:

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

And then declare your class to implement 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) { } } 

Comments

2

The implementation is required to implement the open-generic methods, Import<T> and Export<T>, not closed generic methods, such as Import<string> and Export<string>.

The T is not specified by the implementing class, but by the calling site where you call the method.

Example:

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

If you do want the implementing class to specify the type you can declare it in your interface like this:

public interface ISapFunction <T> { .. } 

And then implement it:

public class SapMaterialFormatter : ISapFunction<string> 

2 Comments

by the calling site I guess it's side instead
@meJustAndrew I guess not
0

You can choose from two different approaches to achieve generic parameters to methods in interface:

Solution 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(); } } 

It consists in defining methods as generic both in interface and in implementing class, and it can be used like this:

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

Solution 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(); } } 

Which consists in declaring the interface as accepting a generic and using it in the methods.

You can then use it as:

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

Note: I have removed the content of the methods just to ensure that the code compiles, you are free to change the samples as you want.

Comments

0

As everyone already explained to you, you have to make your implementation generic too, you can't specify the type.

The main reason for that is, if I do something like this:

interface ISomething { T Method<T>(); } class SomethingWithString : ISomething { public string Method<string>() { return "Hello World !"; } } class SomethingWithInt : ISomething { public int Method<int>() { return 42; } } 

According to you, both of SomethingWithString and SomethingWithInt implement ISomething.

So I could write:

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

And here:

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

Except using an object/dynamic type, we can't know the type returned by Method.

This is why you have to change your implementation, others answers already show you how to do that.

5 Comments

Yeah, i don't think an answer can be: "What everyone else said" unless you really do add some clarity or something new that everyone else missed out
Well, I thought it would be interesting to the OP to know why that don't work, everyone is just talking about how to implement it. If everyone, think is not useful, I will delete this.
@romain-aga Well you can leave there. In my case, I've already explained why it doesn't work... Generic method parameters must be given when the method is called :D
@MatíasFidemraizer I think I should clarify my post, since I'm more in the concept "why this is not allowed", than the "how to implement it". You all have already done that part, no point to do that again.
That should be better now. What do you think ?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.