Можно ли написать метод расширения для абстрактного класса - PullRequest
5 голосов
/ 01 сентября 2010

Почему я не могу расширить абстрактный класс. Есть ли работа для достижения этой цели?

В Silverlight Enum.GetNames отсутствует. Итак, я хотел бы расширить его и включить в мою сборку утилит. К тому времени залез в это.

Ответы [ 2 ]

6 голосов
/ 01 сентября 2010

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

Методы расширения - это статические методы, которые представляются в C # как методы экземпляра. Но они все еще статичны. Добавление статического метода к типу требует возможности переопределить тип, что вы можете сделать, только если у вас есть исходный код:)

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

Однако вполне возможно, что его там нет, потому что он физически не поддерживается в Silverlight (я не знаю - я не расследовал)

EDIT

Исходя из вашего комментария - и я надеюсь, что я вас здесь понял - я думаю, что вы хотите, чтобы иметь возможность сделать что-то вроде этого (цель object, чтобы доказать свою точку зрения):

public static class ExtraObjectStatics
{
  public static void NewStaticMethod()
  {

  }
}

public class Test
{
  public void foo()
  {
    //You can't do this - the static method doesn't reside in the type 'object'
    object.NewStaticMethod();
    //You can, of course, do this
    ExtraObjectStatics.NewStaticMethod();
  }
}

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

Что вы можете сделать, это (и я на самом деле не рекомендую это - но это вариант), создать себе новый тип с именем Enum и поместить его в новое пространство имен:

namespace MySystem
{
  public class Enum
  {
    public static string[] GetNames()
    {
      //don't actually know how you're going to implement it :)
    }
  }
}

А теперь - когда вы хотите его использовать, то, что вы не можете сделать, это:

using System;
using MySystem;

namespace MyCode
{
  public class TestClass
  {
    public static void Test()
    {
      Enum.GetNames(); //error: ambiguous between System and MySystem
    }
  }
}

Поскольку использование в самой внешней области видимости для «System» и «MySystem» приведет к тому, что компилятор не сможет определить правильный тип Enum.

Что вы можете сделать, однако, это:

using System;

namespace MyCode
{
  using MySystem; //move using to inside the namespace
  public class TestClass
  {
    public static void Test()
    {
      //will now work, and will target the 'MySystem.Enum.GetNames()'
      //method.
      Enum.GetNames();
    }
  }
}

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

Таким образом, вы можете думать об этом как о переопределении всего типа Enum в пользу данного пространства имен, включающего в себя using MySystem;.

Но он делает именно это - он заменяет существующего System.Enum на MySystem.Enum - это означает, что вы потеряете всех членов типа System.Enum.

Вы можете обойти это, написав методы-оболочки в вашем типе Enum для System.Enum версий - убедившись, что вы полностью квалифицируете тип как System.Enum.

Посмотрев на реализацию метода GetNames в Reflector - он опирается на внутренние данные, которые я не думаю, что вы сможете построить ... но мне было бы очень интересно услышать, если вы на самом деле способный воспроизвести метод в Silverlight.

4 голосов
/ 01 сентября 2010
public abstract class Foo
{
  public abstract void Bar();
}

public static class FooExtensions
{
  // most useless extension method evar
  public static void CallBar(this Foo me)
  {
    me.Bar();
  }
}

Конечно, нет проблем.

...