2009-08-07 2 views
31

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

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

+0

Может вы разделили свой второй q вопрос в отдельный вопрос? – EFraim

+0

Разбивается на следующую тему: вызов статического метода интерфейса C# с генериками – Toto

+0

Дубликат: http://stackoverflow.com/questions/248263/why-cant-i-declare-c-methods-virtual-and-static –

ответ

51

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

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

+0

мы не называем их функциями :) мы называем их методами –

+1

@ Yassir : Ах, спасибо. Прогулка со мной, как с парнем C++. :) Я исправлю это. – sbi

+0

я wouldlike сделать что-то вроде этого:. ((I) TypeOf (mybject)) MyStaticFunction (с I, интерфейс с MyStaticFunction статической функцией интерфейса) Я знаю синтаксис неверен, но вот точка. – Toto

1

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

21

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

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

«виртуальный» и «статические» противоположны! «Virtual» означает «определить метод, который будет вызываться на основе информации о типе времени выполнения», а «статический» означает «определить метод, который будет называться только на основе статического анализа времени компиляции».

1

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

Из MSDN:

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

Для получения более подробной информации ознакомьтесь с C# Extension Methods (C# Programming Guide).

+0

Методы расширения не отличаются от простых виртуальных. –

5

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

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

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

Давайте соберем вместе пример:

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 указателей функций, и в этом случае одна глобальная структура.

7

Противоречие между «статическим» и «виртуальным» является только проблемой C#. Если бы «статические» были заменены на «уровень класса», как и на многих других языках, никто не был бы с завязанными глазами.

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

Некоторые Delphi красоты:

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

Это не «плохой выбор слов», определение «статический» - * «определяет метод, который будет называться только на основе статического анализа времени компиляции» * в соответствии с ответом Майкла Стама (http: // stackoverflow.com/a/1244431/648265) - это то, что на самом деле означало с момента его введения в C. Запрос функции эффективно меняет свой смысл на «class-bound». –

7

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

1

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

Наиболее хотел использовать случай для того, чтобы иметь заводов, которые могут быть «переопределенными»

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

Пример 1 Давайте возьмем пример фабрики:

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); 
+0

На самом деле это называется «[Любопытно повторяющийся шаблон шаблона] (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)». –

+2

Это имя было изобретен инженером в 1995 году минимум через 6 лет после того, как F-ограниченный полиморфизм был математически формализован. http://bit.ly/1Ft54Ah В то время не было Интернета, хотя я не могу обвинять его в том, что он не смотрел на него (Google был основан в 1999 году) –

+0

Вау, я этого не знал. Добавлено это в статью Википедии. –

0

Суммируя все варианты представлены:

Смежные вопросы