использование статических методов ограниченного универсального типа C # - PullRequest
7 голосов
/ 08 августа 2011

У меня есть универсальный класс:

public class Foo<T> where T: Interface
{

}

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

в конструкторе, который я хочу иметь возможностьв основном сделать следующее:

public Foo()
{
   value1 = T.staticmethod1();
   value2 = T.staticmethod2();
}

Этого нельзя достичь с помощью psuedocode, который я выложил выше.Разве нельзя вызывать эти статические методы таким образом?

Ответы [ 5 ]

9 голосов
/ 08 августа 2011

Вы можете использовать методы расширения. Эта техника была названа псевдо-миксин . Хотя методы расширения на самом деле являются статическими, они «притворяются» методами экземпляра, поэтому вам все еще нужен конкретный экземпляр T.

Кроме того, это своего рода обман, если вы хотите, чтобы ваш интерфейс сохранял свою роль в качестве самодокументируемого «контракта», который определяет, какие методы должен иметь ваш класс T. Однако они безопасны по типу (ваш класс Foo не будет компилироваться, если вы не добавите IBarExtensions в область видимости)

//our interface
public interface IBar {}

// the two static methods are define as extension methods
public static class IBarExtensions {
    public static string someMethod1(this IBar self) {
        return "my initialization 1";
    }
    public static string someMethod2(this IBar self) {
        return "my initialization 2";
    }
}

public class Foo<T> where T : IBar, new()
{
    public string value1 {get; private set;}
    public string value2 {get; private set;}

    public Foo() {
        T t = new T(); // we can do this because of the "new()" constraint
                           // in the class definition
                           // Alternatively we could pass an instance of T in
                           // the constructor 
                           // public Foo(T t)
        value1 = t.someMethod1();
        value2 = t.someMethod2();       
    }
}

тестирование

public class TestBar : IBar {}
void Main()
{
    var c = new TestBar();

    var t = new Foo<TestBar>();
    Console.WriteLine(t.value1);
}
4 голосов
/ 08 августа 2011

Нет, это невозможно.Даже с dynamic. являются общими ограничениями (например, интерфейсами), но это относится только к элементам экземпляра.Вы можете рассмотреть возможность передачи этих методов в (параметры) как Func<T> / Action<T> делегатов?

Кроме того, ваш единственный (и нежелательный) вариант - отражение.Или, может быть, лучше: переосмыслить наш подход здесь.

1 голос
/ 08 августа 2011

Невозможно использовать статические члены ограниченных параметров универсального типа, потому что наличие статического члена в конкретном типе ничего не говорит о том, будет ли производный тип иметь совместимый член с этим именем. Предположим, что тип "Foo" имеет статическую функцию Wowzo (), которая возвращает Int32, тип DerivedFoo1 имеет другую статическую функцию Wowzo (), которая также возвращает Int32, тип DerivedFoo2 (который является производной от Foo), имеет статический член Wowzo () который возвращает String, а тип DerivedFoo3 имеет вложенный класс Wowzo. Если T является параметром типа, являющимся потомком Foo, то что такое T.Wowzo?

1 голос
/ 08 августа 2011

C # не позволяет вам вызывать статические методы, определенные в интерфейсах.Он выдает сообщение об ошибке со слабым именем :

CS0017 также происходит, если вы используете библиотеку, написанную на языке, который допускает статические члены в интерфейсах, и вы пытаетесь получить доступ к статическому членуиз C #.

Если бы C # разрешил это, вы бы использовали имя интерфейса, а не имя общего параметра, чтобы вызывать их:

// doesn't work:
public Foo() {
  value1 = Interface.staticmethod1();
  value2 = Interface.staticmethod2(); 
} 

Итак, у вас естьпара опций:

  1. Используйте язык, который позволяет вызывать этих членов (я думаю, VB.NET и C ++ / CLI позволяют это).Вы можете написать небольшую адаптационную шайбу, которую вы можете использовать из C #;
  2. Попросите людей, которые предоставили вам этот интерфейс (возможно, это даже вы), не использовать статические члены в интерфейсах.Их можно перемещать в отдельные статические классы.Класс может даже быть вложенным в интерфейс (если это позволяет язык), и он будет работать с C #.
0 голосов
/ 08 августа 2011

В качестве оболочки можно также использовать нестатический метод, вызывающий статический метод.Нестатический метод может быть частью вашего интерфейса.

...