Подтвердить что ты не робот

Виртуальный статический метод С#

Почему статическое виртуальное невозможно? Является ли С# зависимым или просто не имеет никакого смысла в мире OO?

Я знаю, что концепция уже подчеркнута, но я не нашел простого ответа на предыдущий вопрос.

4b9b3361

Ответ 1

virtual означает, что указанный метод будет выбран во время выполнения, в зависимости от динамического типа объекта. static означает, что для вызова метода не требуется объект.

Как вы предлагаете делать оба в одном и том же методе?

Ответ 2

У Эрика Липперта есть сообщение в блоге об этом, и, как обычно, с его постов, он охватывает тему на большой глубине:

http://blogs.msdn.com/b/ericlippert/archive/2007/06/14/calling-static-methods-on-type-parameters-is-illegal-part-one.aspx

"виртуальные" и "статические" - противоположности! "virtual" означает "определить метод, который будет вызываться на основе информации о типе времени выполнения", а "статический" означает "определить метод, который будет называться исключительно на основе статического анализа времени компиляции"

Ответ 3

Противоречие между "статическим" и "виртуальным" - это только проблема С#. Если "статические" были заменены на "уровень класса", как и во многих других языках, никто не будет с завязанными глазами.

Слишком плохо выбор слов, сделанных С# калекой в ​​этом отношении. По-прежнему можно вызвать метод Type.InvokeMember для имитации вызова уровня класса, виртуального метода. Вам просто нужно передать имя метода как строку. Отсутствие проверки времени компиляции, отсутствие сильного ввода и отсутствие контроля над тем, что подклассы реализуют этот метод.

Некоторая красота Дельфи:

type
  TFormClass = class of TForm;
var
  formClass: TFormClass;
  myForm: TForm;
begin
  ...
  formClass = GetAnyFormClassYouWouldLike;
  myForm = formClass.Create(nil);
  myForm.Show;
end

Ответ 4

Ребята, которые говорят, что нет смысла в статических виртуальных методах. Если вы не понимаете, как это возможно, это не означает, что это невозможно. Есть языки, которые позволяют это! Посмотрите, например, на Delphi.

Ответ 5

Я собираюсь быть тем, кто на днях. То, что вы описываете, технически не является частью языка. Сожалею. Но его можно смоделировать в пределах языка.

Давайте рассмотрим то, о чем вы просите, - вам нужен набор методов, которые не привязаны к какому-либо конкретному объекту, который может быть легко вызван и заменен во время выполнения или времени компиляции.

Для меня это похоже на то, что вы действительно хотите - это одноэлементный объект с делегированными методами.

Сопоставьте пример:

public interface ICurrencyWriter {
    string Write(int i);
    string Write(float f);
}

public class DelegatedCurrencyWriter : ICurrencyWriter {
    public DelegatedCurrencyWriter()
    {
        IntWriter = i => i.ToString();
        FloatWriter = f => f.ToString();
    }
    public string Write(int i) { return IntWriter(i); }
    public string Write(float f) { return FloatWriter(f); }
    public Func<int, string> IntWriter { get; set; }
    public Func<float, string> FloatWriter { get; set; }
}

public class SingletonCurrencyWriter {
    public static DelegatedCurrencyWriter Writer {
        get {
            if (_writer == null)
               _writer = new DelegatedCurrencyWriter();
            return _writer;
        }
    }
}

в использовании:

Console.WriteLine(SingletonCurrencyWriter.Writer.Write(400.0f); // 400.0

SingletonCurrencyWriter.Writer.FloatWriter = f => String.Format("{0} bucks and {1} little pennies.", (int)f, (int)(f * 100));

Console.WriteLine(SingletonCurrencyWriter.Writer.Write(400.0f); // 400 bucks and 0 little pennies

Учитывая все это, теперь у нас есть одноэлементный класс, который выписывает валютные значения, и я могу изменить его поведение. Я в основном определил соглашение о поведении во время компиляции и теперь могу изменить поведение либо во время компиляции (в конструкторе), либо во время выполнения, что, я считаю, эффект, который вы пытаетесь получить. Если вы хотите наследовать поведение, вы можете сделать это путем реализации обратной цепочки (т.е. Чтобы новый метод вызывал предыдущий).

Тем не менее, я не особо рекомендую приведенный выше пример кода. Во-первых, он не является потокобезопасным, и на самом деле не так много, чтобы поддерживать жизнь. Глобальная зависимость от такого типа структуры означает глобальную нестабильность. Это один из многих способов, с помощью которых изменяемое поведение было реализовано в темные дни C: structs указателей функций, и в этом случае одна глобальная структура.

Ответ 6

В .NET диспетчеризация виртуальных методов (грубо) выполняется путем просмотра фактического типа объекта при вызове метода во время выполнения и нахождения наиболее переопределяющего метода из класса vtable. При вызове статического класса нет экземпляра объекта для проверки, и поэтому нет vtable для поиска.

Ответ 7

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

Из MSDN:

Методы расширения позволяют вам "добавлять", методов для существующих типов без создавая новый производный тип, перекомпилировать или иным образом модифицировать оригинальный тип.

Подробнее о С# Extension Methods (Руководство по программированию на С#).

Ответ 8

Да, это возможно.

Наиболее востребованным вариантом для этого является наличие фабрик, которые могут быть "переопределены"

Для этого вам придется полагаться на параметры типового типа, используя F-ограниченный полиморфизм.

Пример 1 Возьмем пример factory:

class A: { public static A Create(int number) { return ... ;} }
class B: A { /* How to override the static Create method to return B? */}

Вы также хотите, чтобы createB был доступен и возвращал объекты B в классе B. Или вам может потребоваться, чтобы статические функции были библиотекой, которая должна быть расширена B. Решение:

class A<T> where T: A<T> { public static T Create(int number) { return ...; } }
class B: A<B>  { /* no create function */ }
B theb = B.Create(2);       // Perfectly fine.
A thea = A.Create(0);       // Here as well

Пример 2 (продвинутый): Пусть задает статическую функцию для умножения матриц значений.

public abstract class Value<T> where T : Value<T> {
  //This method is static but by subclassing T we can use virtual methods.
  public static Matrix<T> MultiplyMatrix(Matrix<T> m1, Matrix<T> m2) {
    return // Code to multiply two matrices using add and multiply;
  }
  public abstract T multiply(T other);
  public abstract T add(T other);
  public abstract T opposed();
  public T minus(T other) {
    return this.add(other.opposed());
  }
}
// Abstract override
public abstract class Number<T> : Value<T> where T: Number<T> {
  protected double real;

  /// Note: The use of MultiplyMatrix returns a Matrix of Number here.
  public Matrix<T> timesVector(List<T> vector) {
    return MultiplyMatrix(new Matrix<T>() {this as T}, new Matrix<T>(vector));
  }
}
public class ComplexNumber : Number<ComplexNumber> {
  protected double imag;
  /// Note: The use of MultiplyMatrix returns a Matrix of ComplexNumber here.
}

Теперь вы также можете использовать статический метод MultiplyMatrix для возврата матрицы комплексных чисел непосредственно из ComplexNumber

Matrix<ComplexNumber> result = ComplexNumber.MultiplyMatrix(matrix1, matrix2);

Ответ 9

Подводя итог всем представленным опциям: