Вопрос по c#, generics – Интерфейс в качестве аргумента или общий метод, где - в чем разница?

12

Есть ли разница между:

public void Method1<T>(class1 c, T obj) where T:Imyinterface

А также

public void Method2(class1 c, Imyinterface obj)

?

Каковы преимущества использования первого метода?

Я бы сказал, в этом случае они имеют одинаковую функциональность. Jonesopolis
@ Посмотриэтот, Как правило, вы должны избегать наследования интерфейсов в структурах Amit
@ Ли - согласен, мой комментарий был слишком поспешным. Amit
Одно из отличий состоит в том, что при вызове второй версии структуры будут упакованы в рамку, чего следует избегать в общем методе. Lee
@Amit - нет никаких причин, почему структуры не должны реализовывать интерфейсы - фактически они должны реализовыватьIEquatable<T> чтобы избежать бокса на сравнения равенства. Обобщения, подобные вышеприведенному использованию, избегают того самого случая, о котором говорится в ответе! Lee

Ваш Ответ

4   ответа
3

В то время как в вашем сценарии это практически то же самое (за исключением того факта, что при методе, принимающем параметр интерфейса, он будет преобразовывать конкретный объект в тип интерфейса), рассмотрим немного другой сценарий. Допустим, мы хотим, чтобы наш метод принимал только класс, который реализует два интерфейсаIMyInterface1 а такжеIMyInterface2 и этот код не должен компилироваться:

interface IMyInterface1 { }    

interface IMyInterface2 { }

class MyClass : IMyInterface1 { }

public void Method1<T>(Class1 c, T obj) where T : IMyInterface1, IMyInterface2
{

}

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

А какой интерфейс должен отправить пользователь? Он действительно не знает тип, который нужно отправить во время компиляции.

Это хорошее место, чтобы использовать общие и общие ограничения, и с другой стороны, мы не можем использовать один параметр интерфейса.

это ответ, что я ищу Rayet
4

Как уже отмечалось, с пустыми методами, нет большой разницы в использовании.

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

Большая разница возникает при использовании типа возврата.

public T Method1<T>(class1 c, T obj) where T: IMyInterface

а также

public IMyinterface Method2(class1 c, IMyInterface obj)

При использовании универсальной версии вы получаете исходный тип, поэтому вы можете продолжать вызывать свойства или методы (экземпляр или расширение) исходного типа.

С неуниверсальной версией вы получите только значение типаIMyInterface, поэтому вы можете вызывать только те свойства или методы, которые являются частьюIMyInterface.

Это наиболее интересно в моей книге, когда используется с методами расширения и API в свободном стиле.

public static T Move<T>(this T animal) where T : ICanMove
{
    return animal;
}

public static T Fly<T>(this T animal) where T : ICanFly
{
    return animal;
}

public static T Pounce<T>(this T animal) where T : ICanPounce
{

    return animal;
}

Учитывая, что Tiger реализует ICanMove и ICanPounce, а Eagle реализует ICanMove и ICanFly, я могу вызвать вышеупомянутые методы расширения, которые применяются к исходному типу. Intellisense покажет .Fly () и .Move (), доступные для Eagle, и .Pounce () и .Move () для Tiger.

var birdie = new Eagle();

birdie
    .Move()
    .Fly()
    .Move()
    .Fly();

var kitty = new Tiger();

kitty
    .Move()
    .Pounce()
    .Move()
    .Pounce();

Вот как это выглядело бы, если бы вы реализовали Move неуниверсально:

public static ICanMove Move<T>(this ICanMove animal) 
{
    return animal;
}

Поскольку возвращается интерфейс ICanMove, компилятор не знает, что он изначально был Eagle или Tiger, и поэтому вы можете использовать только расширения, методы или свойства, которые являются частью интерфейса ICanMove.

0

Там нет большой разницы дляvoid методы.

public void Method1<T>(class1 c, T obj) where T : Imyinterface

равно

public void Method2(class1 c, Imyinterface obj, Type t)

гдеt должно бытьImyinterface.

Так что если вам нужно передать некоторыеType к вашему методу, и вам нужно применить некоторые ограничения к этомуType во время компиляции используйте универсальный метод.

4

Использование универсального метода дает вам различные возможности с небольшими изменениями подписи:

public void Method1<T>(class1 c, T obj) where T:Imyinterface, new():
Это позволяет создавать новые экземпляры типаT.public T Method1<T>(class1 c, T obj) where T:Imyinterface:
Это позволяет вам использовать метод без приведения его возвращаемого значения при необходимости.public void Method1<T>(class1 c, ref T obj) where T:Imyinterface:
Это позволяет вам придать новое значениеobjСсылка. То же относится и кout.

Это невозможно с не универсальной версией.

@GianPaolo - хорошая мысль, и я немного расширил свой ответ. Amit
чтобы создать экземпляры универсального типа, вы должны добавитьновое ограничение в список ограничений. если нет, он не скомпилируется Gian Paolo

Похожие вопросы