2016-05-30 4 views
0

Я хочу написать интерфейс, который позволяет свободу в реализации. В принципе, я не знаю, какие типы возвращаемых типов не являются параметрами. Я просто хочу, чтобы производные классы реализовали этот контракт с одинаковыми именами методов и номерами параметров.Ошибка компиляции с типами примитивов с реализациями общих методов интерфейса

Так что я могу сделать так:

public interface IImageRecognitionEngine<TFoo0, TFoo1, TFoo2, TFoo3> 
{ 
    TFoo0 Learn(TFoo1 param); 
    TFoo2 Recognize(TFoo3 param); 
} 

public class FooImageRecognitionEngine : IImageRecognitionEngine<byte[], string, List<double>, string> 
{ 
    public byte[] Learn(string param) 
    { 
     throw new NotImplementedException(); 
    } 

    public List<double> Recognize(string param) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Но я бы гораздо больше предпочитают общие методы, а не весь интерфейс. Но я не понимаю, почему я могу это сделать:

public interface IImageRecognitionEngine2 
{ 
    TFoo0 Learn<TFoo0, TFoo1>(TFoo1 param); 
    TFoo2 Recognize<TFoo2, TFoo3>(TFoo3 param); 
} 

public class FooExampleClass 
{ 

} 

public class FooExampleClass2 
{ 

} 

public class Foo1ImageRecognitionEngine2 : IImageRecognitionEngine2 
{ 
    public FooExampleClass Learn<FooExampleClass, FooExampleClass2>(FooExampleClass2 param) 
    { 
     throw new NotImplementedException(); 
    } 

    public FooExampleClass Recognize<FooExampleClass, FooExampleClass2>(FooExampleClass2 param) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Но с примитивными типами компилятор дает мне ошибки:

public class Foo2ImageRecognitionEngine2 : IImageRecognitionEngine2 
{ 
    public byte[] Learn<byte[], string>(string param) 
    { 
     throw new NotImplementedException(); 
    } 

    public List<double> Recognize<List<double>, string>(string param) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Я не хочу, чтобы иметь возможность выбирать, какие типы использовать когда я создаю экземпляр объекта реализации класса. Например, я не хочу, чтобы написать реализацию, как это:

public class Foo2ImageRecognitionEngine2 : IImageRecognitionEngine2 
{ 
    public TFoo0 Learn<TFoo0, TFoo1>(TFoo1 param) 
    { 
     throw new NotImplementedException(); 
    } 

    public TFoo2 Recognize<TFoo2, TFoo3>(TFoo3 param) 
    { 
     throw new NotImplementedException(); 
    } 
} 

И, будучи в состоянии сделать это:

var fooEngine = new Foo2ImageRecognitionEngine2(); 
fooEngine.Learn<string, int>(52); 

И это не работает также:

public interface IImageRecognitionEngine3 
{ 
    object Learn(object param); 
    object Recognize(object param); 
} 

public class Foo1ImageRecognitionEngine3 : IImageRecognitionEngine3 
{ 
    public byte[] Learn(string param) 
    { 
     throw new NotImplementedException(); 
    } 

    public List<double> Recognize(string param) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Спасибо

+0

Но ни одна из ваших реализаций фактически не удовлетворяет интерфейсу. Например, в объекте Learn (object param) я должен иметь возможность передавать что-либо как «param» (поскольку это объект типа), но ваш байт [] Learn (string param) позволяет мне передавать строку, поэтому не удовлетворяют интерфейсу. – Evk

+0

Я думаю, что основным мотивом дженериков является то, что вы пытаетесь обойти. Вы должны * указать тип в конце концов. Я думаю, вы хотите создать «' 'Learn''' и' '' Recognize''' общие, а не метод или интерфейс. И тогда они могут принимать любые типы, которые вы хотите, и вы можете поддерживать интерфейс чистым (и сигнатурами метода)! – Ruskin

+0

Есть ли у вас пример кода для обмена? Я не уверен, что понял. Я хочу использовать мой интерфейс в своей программе и передать хорошую реализацию при запуске, используя инъекцию зависимостей. Подобным образом я бы смог изменить реализацию, которую я использую очень легко. –

ответ

2
public FooExampleClass Learn<FooExampleClass, FooExampleClass2>(FooExampleClass2 param) 
{ 
    throw new NotImplementedException(); 
} 

не делает то, что вы думаете - FooExampleClass и FooExampleClass2 - это не типы, а параметры типа, которые могут быть созданы для любого класса. Это означает, что клиент может сделать:

var e = new Foo1ImageRecognitionEngine2(); 
e.Learn<string, object>(new object()); 

Ваш код работает только потому, что он ничего не делает.

Общие методы, подобные этому, должны работать для любых параметров, которые выбирает клиент, поэтому нет способа ограничить работу параметров для определенных параметров. Если вы хотите это сделать, вам нужно перенести их в определение интерфейса, которое у вас есть в первом примере.

+0

Хорошо спасибо за ваш ответ. Я думал, что в моем случае было возможно использовать только общие методы, не используя общий интерфейс, но, похоже, это не так. Поскольку количество методов будет расти, классы реализации будут выглядеть довольно уродливыми и трудными для чтения –

Смежные вопросы