Почему C # реализует методы как не виртуальные по умолчанию? -- c# поле с участием java поле с участием .net поле с участием virtual-functions пол Связанный проблема

Why C# implements methods as non-virtual by default?


105
vote

проблема

русский

В отличие от Java, почему C # методы лечения как не виртуальные функции по умолчанию? Скорее всего, это проблема производительности, а не на других возможных результатах?

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

Английский оригинал

Unlike Java, why does C# treat methods as non-virtual functions by default? Is it more likely to be a performance issue rather than other possible outcomes?

I am reminded of reading a paragraph from Anders Hejlsberg about several advantages the existing architecture is bringing out. But, what about side effects? Is it really a good trade-off to have non-virtual methods by default?

</div
           
     
     

Список ответов

98
 
vote
vote
Лучший ответ
 

классы должны быть разработаны для наследования, чтобы иметь возможность воспользоваться этим. Имение методов <Код> virtual по умолчанию означает, что каждая функция в классе может быть подключена и заменена другим, что не очень хорошая вещь. Многие люди даже считают, что классы должны были быть <код> sealed по умолчанию.

<Код> virtual Методы также могут иметь небольшое значение производительности. Однако это вряд ли будет основной причиной.

 

Classes should be designed for inheritance to be able to take advantage of it. Having methods virtual by default means that every function in the class can be plugged out and replaced by another, which is not really a good thing. Many people even believe that classes should have been sealed by default.

virtual methods can also have a slight performance implication. This is not likely to be the primary reason, however.

</div
 
 
         
         
89
 
vote

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

Большинство обоснований читают мне, как старые «Если мы дадим вам силу, которую вы можете причинить вреда» аргументу. От программистов?!

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

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

Не виртуально-по умолчанию делает мою жизнь сложнее.

<Сильное> Обновление: Это было указано [вполне правильно], что я на самом деле не ответил на вопрос. Итак - и с извинениями за то, что они достаточно поздно ....

Я вроде хотела иметь возможность написать что-то содержательное, как "C #, реализует методы как не виртуальные по умолчанию, потому что плохое решение было сделано, какие программы более высоко, чем программисты». (Я думаю, что это может быть несколько оправдано, основываясь на некоторых других ответах на этот вопрос - как производительность (преждевременная оптимизация, любой?) Или гарантирует поведение классов.)

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

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

Теперь я думаю, что точная причина, по которой они сделали это решение, мы никогда не ... О, подождите! Стенограмма разговора!

Так что кажется, что ответы и комментарии здесь о опасности переопределения API и необходимость явного дизайна для наследования находятся на правильном пути, но все, что отсутствуют важным временным аспектом: главная забота «Андерса» было о поддержании класса или неявный контракт API через версий . И я думаю, что он на самом деле беспокоит, что позволяет платформу .NET / C # изменять под кодом, а не обеспокоен изменением пользовательского кода сверху платформы. (И его «прагматичный» точка зрения является точной противоположной моей, потому что он смотрит с другой стороны.)

(но не могло бы они просто выбрать виртуальные по умолчанию, а затем перец «финал» через кодовую базу? Возможно, это не совсем то же самое .. и Андерс явно умнее меня, так что я собираюсь позволить ему ложь.)

 

I'm surprised that there seems to be such a consensus here that non-virtual-by-default is the right way to do things. I'm going to come down on the other - I think pragmatic - side of the fence.

Most of the justifications read to me like the old "If we give you the power you might hurt yourself" argument. From programmers?!

It seems to me like the coder who didn't know enough (or have enough time) to design their library for inheritance and/or extensibility is the coder who's produced exactly the library I'm likely to have to fix or tweak - exactly the library where the ability to override would come in most useful.

The number of times I've had to write ugly, desperate work-around code (or to abandon usage and roll my own alternative solution) because I can't override far, far outweighs the number of times I've ever been bitten (e.g. in Java) by overriding where the designer might not have considered I might.

Non-virtual-by-default makes my life harder.

UPDATE: It's been pointed out [quite correctly] that I didn't actually answer the question. So - and with apologies for being rather late....

I kinda wanted to be able to write something pithy like "C# implements methods as non-virtual by default because a bad decision was made which valued programs more highly than programmers". (I think that could be somewhat justified based on some of the other answers to this question - like performance (premature optimisation, anyone?), or guaranteeing the behaviour of classes.)

However, I realise I'd just be stating my opinion and not that definitive answer that Stack Overflow desires. Surely, I thought, at the highest level the definitive (but unhelpful) answer is:

They're non-virtual by default because the language-designers had a decision to make and that's what they chose.

Now I guess the exact reason that they made that decision we'll never.... oh, wait! The transcript of a conversation!

So it would seem that the answers and comments here about the dangers of overriding APIs and the need to explicitly design for inheritance are on the right track but are all missing an important temporal aspect: Anders' main concern was about maintaining a class's or API's implicit contract across versions. And I think he's actually more concerned about allowing the .Net / C# platform to change under code rather than concerned about user-code changing on top of the platform. (And his "pragmatic" viewpoint is the exact opposite of mine because he's looking from the other side.)

(But couldn't they just have picked virtual-by-default and then peppered "final" through the codebase? Perhaps that's not quite the same.. and Anders is clearly smarter than me so I'm going to let it lie.)

</div
 
 
         
         
17
 
vote

Потому что слишком легко забыть, что метод может быть переопределен и не дизайн для этого. C # заставляет вас думать, прежде чем сделать это виртуальным. Я думаю, что это отличное проектное решение. Некоторые люди (такие как Jon Skeet) даже сказали, что классы должны быть запечатаны по умолчанию.

 

Because it's too easy to forget that a method may be overridden and not design for that. C# makes you think before you make it virtual. I think this is a great design decision. Some people (such as Jon Skeet) have even said that classes should be sealed by default.

</div
 
 
12
 
vote

Чтобы обобщить то, что сказали другие, есть несколько причин:

1 - в C #, есть много вещей в синтаксисе и семантике, которые приходят прямо из C ++. Тот факт, что методы, где не виртуальные по умолчанию в C ++ влияют на C #.

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

3 - Самое главное, если методы не являются виртуальными по умолчанию, вы можете гарантировать поведение ваших классов. Когда они являются виртуальными по умолчанию, например, в Java, вы даже не можете гарантировать, что простой метод Getter будет делать как предполагалось, потому что он может быть переопределен, чтобы сделать что-либо в полученном классе (конечно, вы можете, и должен сделать метод и / или финал класса).

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

 

To summarize what others said, there are a few reasons:

1- In C#, there are many things in syntax and semantics that come straight from C++. The fact that methods where not-virtual by default in C++ influenced C#.

2- Having every method virtual by default is a performance concern because every method call must use the object's Virtual Table. Moreover, this strongly limits the Just-In-Time compiler's ability to inline methods and perform other kinds of optimization.

3- Most importantly, if methods are not virtual by default, you can guarantee the behavior of your classes. When they are virtual by default, such as in Java, you can't even guarantee that a simple getter method will do as intended because it could be overridden to do anything in a derived class (of course you can, and should, make the method and/or the class final).

One might wonder, as Zifre mentioned, why the C# language did not go a step further and make classes sealed by default. That's part of the whole debate about the problems of implementation inheritance, which is a very interesting topic.

</div
 
 
 
 
9
 
vote

C # влияет C ++ (и более). C ++ не позволяет Dynamic Dispatch (виртуальные функции) по умолчанию. Один (хороший?) Аргумент за это вопрос: «Как часто вы реализуете классы, которые являются членами класса Hiargy?». Другая причина, чтобы избежать включения динамической отправки по умолчанию - это след памяти. Класс без виртуального указателя (VPOINTER), указывающий на Виртуальный стол , не очень меньше Соответствующий класс с поздним связыванием включен.

Проблема производительности не так легко сказать «да» или «нет». Причина этого является компиляцией как только во времени (JIT), которая представляет собой оптимизацию времени выполнения в C #.

Другой, похожий вопрос о " Скорость виртуальных вызовов. < / a> "

 

C# is influenced by C++ (and more). C++ does not enable dynamic dispatch (virtual functions) by default. One (good?) argument for this is the question: "How often do you implement classes that are members of a class hiearchy?". Another reason to avoid enabling dynamic dispatch by default is the memory footprint. A class without a virtual pointer (vpointer) pointing to a virtual table, is ofcourse smaller than the corresponding class with late binding enabled.

The performance issue is not so easy to say "yes" or "no" to. The reason for this is the Just In Time (JIT) compilation which is a run time optimization in C#.

Another, similar question about "speed of virtual calls.."

</div
 
 
   
   
5
 
vote

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

с не виртуальным методом у вас есть полный контроль. Все, что идет не так, это вина оригинального автора. Код гораздо проще для рассуждения.

 

The simple reason is design and maintenance cost in addition to performance costs. A virtual method has additional cost as compared with a non-virtual method because the designer of the class must plan for what happens when the method is overridden by another class. This has a big impact if you expect a particular method to update internal state or have a particular behavior. You now have to plan for what happens when a derived class changes that behavior. It's much harder to write reliable code in that situation.

With a non-virtual method you have total control. Anything that goes wrong is the fault of the original author. The code is much easier to reason about.

</div
 
 
 
 
2
 
vote

Если все методы C # были виртуальными, то VTBL будет намного больше.

Объекты

C # имеют только виртуальные методы, если класс имеет определенные виртуальные методы. Это правда, что все объекты имеют информацию, которая включает в себя эквивалент VTBL, но если не определены виртуальные методы, то будут присутствовать только методы базового объекта.

@tom Hawtin: Вероятно, точнее сказать, что C ++, C # и Java все из семейства языков C :)

 

If all C# methods were virtual then the vtbl would be much bigger.

C# objects only have virtual methods if the class has virtual methods defined. It is true that all objects have type information that includes a vtbl equivalent, but if no virtual methods are defined then only the base Object methods will be present.

@Tom Hawtin: It is probably more accurate to say that C++, C# and Java are all from the C family of languages :)

</div
 
 
 
 
1
 
vote

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

Рассмотрим метод добавления класса списка. Что если разработчик хотел обновить одну из нескольких потенциальных баз данных, когда определенный список «добавлен»? Если «Добавить» было виртуальным по умолчанию разработчик может создать класс «BackedList», что отменяет метод «Добавить», не заставляя весь код клиента знать, что это был «BackedList» вместо обычного «Списка». Для всех практических целей «Backedist» можно рассматривать как просто еще один «список» от клиентского кода.

Это имеет смысл с точки зрения большого основного класса, который может обеспечить доступ к одному или нескольким компонентам списка, которые сами поддерживаются одним или несколькими схемами в базе данных. Учитывая, что методы C # не являются виртуальными по умолчанию, список, предоставленный основным классом, не может быть простым iEnumerable или ICOLLECTION или даже экземпляром списка, но вместо этого должен быть объявлен клиентом в качестве «задней панели», чтобы убедиться, что новая версия из операции «Добавить» вызывается для обновления правильной схемы.

 

Coming from a perl background I think C# sealed the doom of every developer who might have wanted to extend and modify the behaviour of a base class' thru a non virtual method without forcing all users of the new class to be aware of potentially behind the scene details.

Consider the List class' Add method. What if a developer wanted to update one of several potential databases whenever a particular List is 'Added' to? If 'Add' had been virtual by default the developer could develop a 'BackedList' class that overrode the 'Add' method without forcing all client code to know it was a 'BackedList' instead of a regular 'List'. For all practical purposes the 'BackedList' can be viewed as just another 'List' from client code.

This makes sense from the perspective of a large main class which might provide access to one or more list components which themselves are backed by one or more schemas in a database. Given that C# methods are not virtual by default, the list provided by the main class cannot be a simple IEnumerable or ICollection or even a List instance but must instead be advertised to the client as a 'BackedList' in order to ensure that the new version of the 'Add' operation is called to update the correct schema.

</div
 
 
     
     
0
 
vote

Это, безусловно, не проблема производительности. Sun's Java Transter использует тот же код для отправки (<код> invokevirtual Bytecode) и горячая точка генерирует ровно один и тот же код, будь <код> final или нет. Я считаю, что все объекты C # (но не структуры) имеют виртуальные методы, поэтому вам всегда понадобится <код> vtbl / идентификация класса выполнения. C # - это диалект «Java-подобных языкам». Предложить это из C ++ не совсем честно.

<Р> Существует идея, что вы должны «разработать для наследования, либо запретить его». Что звучит как отличная идея, вплоть до того момента, когда у вас есть серьезное деловое дело, чтобы положить в быстрое исправление. Возможно, унаследовав от кода, который вы не контролируете.
 

It is certainly not a performance issue. Sun's Java interpreter uses he same code to dispatch (invokevirtual bytecode) and HotSpot generates exactly the same code whether final or not. I believe all C# objects (but not structs) have virtual methods, so you are always going to need the vtbl/runtime class identification. C# is a dialect of "Java-like languages". To suggest it comes from C++ is not entirely honest.

There is an idea that you should "design for inheritance or else prohibit it". Which sounds like a great idea right up to the moment you have a severe business case to put in a quick fix. Perhaps inheriting from code that you don't control.

</div
 
 
   
   

Связанный проблема

8  Почему я не могу удалить это cookie?  ( Why cant i delete this cookie ) 
Хорошо, вот 411 - у меня есть следующий обработчик событий в моем файле Global.Asax.cs: <код> private void Global_PostRequestHandlerExecute(object sender, E...

0  Анимация спрайты в XNE после мыши  ( Sprite animation in xna following the mouse ) 
Моя старая проблема заключалась в том, что мой код изначально следит за мышью, но когда она достигла мыши, она исчезла, и в конечном итоге исчезла. Моя теку...

1  Получение релевантности упорядоченный результат из текстового запроса на коллекции MongoDB с использованием драйвера C #  ( Retrieve relevance ordered result from text query on mongodb collection using th ) 
Я пытаюсь отправить текстовые запросы коллекции и получить результаты в текстовом порядке. документы объяснить довольно хорошо, как это сделать в оболочке: ...

5  Использование Litjson в Unity3D  ( Using litjson in unity3d ) 
2 вопроса. 1) Можно ли использовать библиотеку Litjson AS так же, как и сценарии в JavaScript? Это действительно общий вопрос о том, чтобы иметь возможность...

0  Соединение не было закрыто. Текущее состояние соединения открыто  ( Connection was not closed connections current state is open ) 
Это дает сообщение об ошибках не было закрыто. Текущее состояние соединения открыто. Пожалуйста, помогите с кодом. <код> private void comboBox1_SelectedIn...

9  DataTable не выпускает память  ( Datatable does not release memory ) 
У меня есть процесс загрузки данных, который загружает большую сумму данных в DataTable, затем выполняет некоторые данные, но каждый раз, когда задание заверш...

0  Не читайте текстовые данные на таблицу SQL в C #  ( Not reading text data to sql table in c sharp ) 
Поэтому я следовал большему количеству помощи, которую я мог найти здесь. Я создал программу C #, которая читает из текстового файла и вставляет в таблицу баз...

5  сериализовать два разных экземпляра в списке на одну строку JSON  ( Serialize two different instances in a list to a single json string ) 
У меня есть два типа классов: <код> public class HolidayClass { public int ID { get; set; } public string Name { get; set; } public DateTime Sta...

1  Visual Studio C # KeyDown блокирует друг друга  ( Visual studio c sharp keydown blocking each other ) 
Есть ли способ сделать два ключа работать одновременно, поэтому они не блокируют друг друга? <код> private void multiplayer_KeyDown(object sender, KeyEv...

0  Написание одного символа за раз в приложении консоли C #?  ( Writing one character at a time in a c sharp console application ) 
Я не уверен, как это объяснить ... В основном я хочу иметь возможность писать строки текста в консоли, как старые RPG, используемые для записи диалога, один...

0  WCF Post Method Получить ошибку 400 плохой запрос  ( Wcf post method get error 400 bad request ) 
Я использую метод WCF Post, как только я добавил PARAMETER POST на службу, его ошибка возврата 400 плохой запрос, если я оставил параметр пустой, он может пол...

0  Как загрузить каталог на FTP, используя ftplib?  ( How to upload directory to ftp using ftplib ) 
У меня проблемы с загрузкой Все файлы на FTP: я использую ftplib . У меня есть функция для загрузки: <код> Proj executable not found. Please set PROJ_DIR v...

1  WCF Callback Doblocks даже с «iSineynchronInationContext = False»  ( Wcf callback deadlocks even with usesynchronizationcontext false ) 
Я застрял с проблемой, которую я не могу понять. Проблема связана с синхронизацией между потоками на стороне клиента, но я не могу найти корневую причину эт...

0  Создание ссылки IPC между плагинами APC Java и C #  ( Establishing ipc link between a java app and c based plugins ) 
У нас есть приложение Java, а также ряд плагинов C #, для других приложений (например, Excel), которые могут взаимодействовать с основным приложением. Слой св...

1  Получение строки сразу после вставки возвращается нет результата  ( Getting row right after insert returns no result ) 
Я бегут тесты подразделения, и когда я пытаюсь вставить данные в базу данных и получить его сразу после того, как я ничего не получаю (я пробовал с <код> Data...

Связанный проблема

8  Почему я не могу удалить это cookie? 
0  Анимация спрайты в XNE после мыши 
1  Получение релевантности упорядоченный результат из текстового запроса на коллекции MongoDB с использованием драйвера C # 
5  Использование Litjson в Unity3D 
0  Соединение не было закрыто. Текущее состояние соединения открыто 
9  DataTable не выпускает память 
0  Не читайте текстовые данные на таблицу SQL в C # 
5  сериализовать два разных экземпляра в списке на одну строку JSON 
1  Visual Studio C # KeyDown блокирует друг друга 
0  Написание одного символа за раз в приложении консоли C #? 
0  WCF Post Method Получить ошибку 400 плохой запрос 
0  Как загрузить каталог на FTP, используя ftplib? 
1  WCF Callback Doblocks даже с «iSineynchronInationContext = False» 
0  Создание ссылки IPC между плагинами APC Java и C # 
1  Получение строки сразу после вставки возвращается нет результата