C # универсальный конструктор копирования - PullRequest
5 голосов
/ 19 февраля 2009

У меня есть интерфейс и два класса, которые реализуют интерфейс. У классов есть универсальные типы. Я хотел бы клонировать из экземпляра одного класса в другой.

interface IFoo
{
    // stuff
}

class Foo<T> : IFoo
{
    // foo stuff
    // ifoo implementation
}

class Bar<T> : IFoo
{
    // bar stuff
    // ifoo implementation
}

У меня есть Foo и я бы хотел бар. Bar имеет конструктор копирования, принимающий параметр IFoo. Я создал метод расширения для реализации клона:

public static Bar<T> Clone<T>(this IFoo foo) 
{
    return new Bar<T>(foo);
}

Для вызова метода требуется тип:

someFoo.Clone<T> ...

Есть ли способ пропустить объявление типа при вызове метода путем изменения метода расширения или любым другим способом, чтобы экземпляр мог быть просто передан без заботы о его базовом типе?

Обновление Вот как это используется, чтобы лучше проиллюстрировать ситуацию.

В методе я повторяю коллекцию и возвращаю перечисление IFoo. В методе я смотрю на атрибут исходной коллекции и определяю тип Foo.

IFoo foo = null;

string type = element.Attribute("Type").Value;
switch (type)
{
    case "int":
        foo = new Foo<int>();
        break;

    case "string":
        foo = new Foo<string>();
        break;

    // etc
}
// other stuff

yield return foo;

У вызывающего метода есть List. Позже я выбираю отдельные элементы из этого списка для использования, и в этот момент я предпочитаю панель вместо Foo. При выборе из списка экземпляры имеют тип IFoo, так как они видят только методы расширения для «this IFoo foo». Я не хочу приводить IFoo к Foo, что потребовало бы повторного объявления типа T. Я просто хотел бы, чтобы Foo сказал Bar, что это такое. Это возможно?

Ответы [ 5 ]

2 голосов
/ 19 февраля 2009

Итак, у вас все в порядке, но вы хотите использовать синтаксис

someFoo.Clone()

вместо

someFoo.Clone<int>()

Вы хотите, чтобы int подразумевался вместо того, чтобы явно указывать его?

Причина, по которой вы не можете сделать это в своем примере кода, заключается в том, что IFoo не ссылается на универсальный тип T, который вам нужен для создания Bar<T>.

Я бы предположил, что вам действительно нужен другой интерфейс: IFoo<T>

Если у вас это было, и ваш метод расширения выглядит следующим образом:

public static Bar<T> Clone<T>(this IFoo<T> foo) 
{
    return new Bar<T>(foo);
}

Тогда у вас не будет проблем с использованием

IFoo<int> someFoo = new Foo<int>();
Bar<int> someBar = someFoo.Clone();

Надеюсь, что поможет

0 голосов
/ 19 февраля 2009

Попробуйте определить метод как таковой

public static Bar<T> Clone<T>(this Foo<T> foo)
{
    return new Bar<T>(foo);
}

Таким образом, параметр будет иметь универсальный тип, а компилятор будет иметь источник для вывода типа из.

0 голосов
/ 19 февраля 2009

Если это работает для вашего сценария, вы можете получить IFoo<T>. Также, если вы не возражаете против использования конкретных методов расширения, вы можете просто получить Foo<T>. Вам действительно нужно передать что-то, что ссылается на T, чтобы компилятор мог вывести соответствующий тип.

0 голосов
/ 19 февраля 2009

Когда вам нужен полный контроль над клоном глубокой копии, этот шаблон очень хорош:

public class FooBase
{
    private int x;

    public FooBase() { /* standard contructor */ }

    protected FooBase(FooBase clone)
    {
        this.x = clone.x;
    }

    public FooBase Clone() { return new FooBase(this); }
}

public class Foo : FooBase
{
    private int y;

    public Foo() { /* standard contructor */ }

    protected Foo(Foo clone) : base(clone)
    {
        this.y = clone.y;
    }

    public Foo Clone() { return new Foo(this); }
}

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

Обновление : Мне кажется, я неправильно понял вопрос и уже внедрил клонирование. Фредди прав - компилятор должен знать, какой тип он должен вывести, и он не может сделать это из типа IFoo. Он может сделать это в (это Foo foo) хотя.

0 голосов
/ 19 февраля 2009

Поможет ли это для вдохновения? Как бы вы улучшили этот класс мелкого копирования?

По сути, это общий метод копирования свойств на основе отражения. Попробуйте.

...