Может ли анонимный класс C # реализовать интерфейс?

356

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

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

public interface DummyInterface
{
    string A { get; }
    string B { get; }
}

public class DummySource
{
    public string A { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

public class Test
{
    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values);

    }

    public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

Я нашел статью Динамическая упаковка интерфейса, которая описывает один подход. Это лучший способ сделать это?

  • 2
    Немного не по теме, но можно ли это сделать на Java? Я уверен, что я видел, что это где-то сделано ...
  • 0
    C4H5As: Я согласен, я уже видел это и раньше. Может быть, VB.Net может это сделать? Или, может быть, я просто думаю о Java.
Показать ещё 4 комментария
Теги:
anonymous-types

7 ответов

271
Лучший ответ

Нет, анонимные типы не могут реализовать интерфейс. Из руководства С#:

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

  • 26
    +1 - Использование анонимных типов обычно должно быть ограничено лямбда-выражениями и выражениями LINQ ... как только данные становятся доступными для вызывающих, которые должны «что-то делать» с объектом, очень хорошая идея реализовать конкретный класс ,
  • 7
    @Mark: мне также нравится использовать анонимные типы в качестве DTO. С автоматическим отображением работает довольно хорошо в некоторых сценариях.
Показать ещё 8 комментариев
73

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

Еще в 2008 году я писал пользовательского провайдера LINQ для моего работодателя, и в какой-то момент мне нужно было сказать "мои" анонимные классы из других анонимных, что означало, что они реализуют интерфейс, который я мог бы использовать чтобы напечатать их. Способ, которым мы это решали, заключался в использовании аспектов (мы использовали PostSharp), чтобы добавить реализацию интерфейса непосредственно в IL. Таким образом, на самом деле предоставление анонимным классам реализации интерфейсов выполнимо, вам просто нужно немного свернуть правила, чтобы добраться туда.

  • 46
    Именно такого поведения я активно избегаю. Скомпилируйте на другой машине, и все это вылетит.
  • 23
    Мне нравится гнуть часть правил;)
Показать ещё 7 комментариев
37

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

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

select new
{
  A = value.A,
  B = value.C + "_" + value.D
};

с

 select new DynamicObject(new
 {
   A = value.A,
   B = value.C + "_" + value.D
 }).CreateDuck<DummyInterface>();
  • 17
    Impromptu-Interface Project будет делать это в .NET 4.0 с использованием DLR и будет легче, чем Linfu.
  • 0
    Является ли DynamicObject типа Линьфа? System.Dynamic.DynamicObject имеет только защищенный конструктор (по крайней мере, в .NET 4.5).
Показать ещё 1 комментарий
12

Лучшее решение - это не использовать анонимные классы.

public class Test
{
    class DummyInterfaceImplementor : IDummyInterface
    {
        public string A { get; set; }
        public string B { get; set; }
    }

    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new DummyInterfaceImplementor()
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values.Cast<IDummyInterface>());

    }

    public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

Обратите внимание, что вам нужно передать результат запроса в тип интерфейса. Возможно, лучший способ это сделать, но я не смог найти его.

  • 2
    Вы можете использовать values.OfType<IDummyInterface>() вместо приведения. Он возвращает только те объекты в вашей коллекции, которые действительно могут быть приведены к этому типу. Все зависит от того, что вы хотите.
11

Нет; анонимный тип не может сделать ничего, кроме нескольких свойств. Вам нужно будет создать свой собственный тип. Я не читал связанную статью в глубину, но похоже, что она использует Reflection.Emit для создания новых типов "на лету"; но если вы ограничиваете обсуждение вещами внутри самого С#, вы не можете делать то, что хотите.

  • 0
    И важно отметить: свойства могут также включать функции или пустоты (Action): выберите new {... MyFunction = new Func <string, bool> (s => value.A == s)}, хотя вы не можете обратиться к новые свойства в ваших функциях (мы не можем использовать «A» вместо «value.A»).
  • 2
    Ну, разве это не свойство, являющееся делегатом? На самом деле это не метод.
Показать ещё 1 комментарий
10

Анонимные типы могут реализовывать интерфейсы через динамический прокси.

Я написал метод расширения GitHub и сообщение в блоге http://wblo.gs/feE для поддержки этого сценарий.

Метод можно использовать следующим образом:

class Program
{
    static void Main(string[] args)
    {
        var developer = new { Name = "Jason Bowers" };

        PrintDeveloperName(developer.DuckCast<IDeveloper>());

        Console.ReadKey();
    }

    private static void PrintDeveloperName(IDeveloper developer)
    {
        Console.WriteLine(developer.Name);
    }
}

public interface IDeveloper
{
    string Name { get; }
}
6

Ответ на заданный вопрос - нет. Но вы смотрели на насмешливые рамки? Я использую MOQ, но там их миллионы, и они позволяют вам реализовать/заглушить (частично или полностью) интерфейсы в режиме онлайн. Например.

public void ThisWillWork()
{
    var source = new DummySource[0];
    var mock = new Mock<DummyInterface>();

    mock.SetupProperty(m => m.A, source.Select(s => s.A));
    mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));

    DoSomethingWithDummyInterface(mock.Object);
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню