Can .NET function in exactly the same way without using the Object type?

I am asking this because it seems that using Object seems like a simple way out to solve certain problems, such as "I don't have a specific type, so use Object", etc.

Also the reason is that I was curious, because my colleague told me that if .NET was a real object-oriented platform, then it would not have to catch the whole type, for example Object.

So, if .NET does not have an Object type, what will be the alternative ways to solve the problems that arise, to make it function in exactly the same way?

It is also simple to note that this is not for bash.NET, since I use it daily in my work. Just want to know more about this.

EDIT: Another note that I remember is that the Object type exists, its effect pulsates throughout .NET. Like IEnumerable, but also IEnumerable <T>. And in many situations, you need to implement both a general and non-general version of things, etc.

+7
c # types type-systems bcl
source share
9 answers

I would say that the problem solved by Object is not "I don’t have a specific type, so use Object", but rather "I don’t care what type it is, all I need to know is Object "

+3
source share

This convenience is not only for use as a "universal" type, but also for reflection, garbage collection, etc.

Other languages ​​(C ++) can do without, but I would be embarrassed to say what makes these languages ​​more OOP.

+3
source share

Your friend is probably working with a dynamic language (like ruby ​​or python), right?

There are so many people who think that strongly typed languages ​​should be called "class-oriented" rather than "object-oriented", because all possible behaviors and polymorphism should be performed in the class definition. When your method accepts anything, any checks are performed based on the capabilities of the objects, and not its class, we can say that this is a more object-oriented approach.

I seemed to contradict this argument. There is such a polite belief in programming circles that OO is definitely Good, no matter what the problem or requirements. Because of this, people tend to try to win arguments by saying that “such and such is not object oriented,” and since object oriented is synonymous with good, they win. Despite the fact that I think that static languages ​​are a pain for work, I think that calling them not OO is an insincere way to make your point. On the other hand, everything that makes a programmer go beyond his comfort zone and learn a new way to do something (if not for any other reason to win the argument) cannot be absolutely bad. As I said, conflict. :)

+3
source share

In a strongly typed structure, objects must start somewhere.

The object type does not exist to provide an “easy” option to select “everything else” or to force you to reset to the lowest common denominator. It should provide the absolute most common case for an object - the basis for comparing links and the convenient ToString() method, among several others.

+2
source share

Remember that inheritance means an is-a relationship. Each class in .NET "is (n)" an object. They all have a ToString method. All of them are of the type with which you get access through GetType . This relationship and the resulting exchange of functionality are the basis of object-oriented programming.

+2
source share

Yes, the type of an object may be misused, but it provides semantic functionality for the .NET world (primarily IMO - GetType ()). Therefore, if there is a problem, this is not with the type of object.

There are many alternatives, including Generics and OOP methods, such as interfaces ...

+1
source share

If the hierarchy of derivation of objects did not have a single unified head, then it would be impossible to verify the equality between any two arbitrary ... uh ... things without resorting to dynamic typing.

In addition, I suspect that the functionality of the object could be handled in approximately the same way by separate interfaces (IEqualable and IConvertableToString). On the other hand, virtual methods of objects are sometimes quite convenient, especially ToString, which can be used by the IDE or debugger when displaying the state of a program. It is truly a pragmatic design.

+1
source share

I am by no means very well versed in this matter, but from my point of view it was useful to allow people to create polymorphic components without first knowing how these components will be consumed. What I mean? Let me try to explain.

Take a simple example with the .NET framework class ArrayList . This was part of the original structure prior to the introduction of Generics. The authors of the ArrayList class tried to provide a useful implementation of a dynamic list, but they had no way of knowing which objects would be inserted into the list. They used the type of the object to represent the elements in the list, since it allowed any type of class to be added to the list. For example:

  ArrayList people = new ArrayList(); people.Add(new Doctor()); people.Add(new Lawyer()); people.Add(new PetDetective()); people.Add(new Ferrari()); // Yikes! // ... for (int i = 0; i < people.Count; i++) { object person = people[0]; // ... } 

Now, if this was your own application, and you knew that your Doctor , Lawyer and PetDetective all derived from the common base Person class, then you could theoretically build your own linked list based on the Person class, not the Object class. However, there is a lot of extra work for very little use when you already have the built-in and tested ArrayList class. If you really want to make it specific to your base Person class, then you can always create a wrapper class for ArrayList that accepts only Person measurable objects.

In C ++, you can do almost the same thing using the data type "void pointer" ( void* ). However, C ++ also supported templates (very similar to generics), which greatly simplified the collection of a useful component, not knowing the details of what other classes it will be used with. Since C # did not support generators at first, using the Object type was really the only way to create common polymorphic components for other people.

+1
source share

The idea that the concept of System.Object can be replaced by interfaces, which are usually implemented by all classes, has been mentioned several times on this issue. Although I think the idea is correct, in the end I would say that it does not buy anything. Even if such interfaces existed, the question would still be how the compiler would actually ensure that classes implement these interfaces.

Below is an example of code in which I am trying to investigate a hypothetical situation where there is no System.Object type and how the implementation might look under the hood, as well as the use of these interfaces.

 // let start off by defining interfaces to describe the various methods that are currently available from the System.Object class public interface IEquatable { bool Equals(IEquatable other); } public interface IHashCodeGenerator { int GetHashCode(); } public interface ITypeIdentifiable { Type GetType(); } public interface IConvertibleToString { string ToString(); } // This guy throws a wrench into things, because we can't privately (or "protectedly") implement an interface. // This is discussed further below on the MyClass.MemberwiseClone method. public interface IMemberwiseCloneable { } // This class simply encapsulates similar functionality found within the System.Object class public static class ClrInternals { [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Equals(IEquatable objA, IEquatable objB); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern int GetHashCode(IHashCodeGenerator hashGenerator); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern Type GetType(ITypeIdentifiable typedInstance); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern IMemberwiseCloneable MemberwiseClone(IMemberwiseCloneable original); } // let say that as a rule the compiler implicitly makes all classes implement these interfaces class MyClassExampleA : IEquatable, IHashCodeGenerator, ITypeIdentifiable, IConvertibleToString, IMemberwiseCloneable { // The compiler also implicitly makes all classes implement the interfaces with the following code (unless otherwise specified) #region IEquatable Members public bool Equals(IEquatable other) { // let suppose that this is equivalent to the current implementation of Object.Equals return ClrInternals.Equals(this, other); } #endregion #region IHashCodeGenerator Members public int GetHashCode() { // let suppose that this is equivalent to the current implementation of Object.GetHashCode return ClrInternals.GetHashCode(this); } #endregion #region ITypeIdentifiable Members public Type GetType() { // let suppose that this is equivalent to the current implementation of Object.GetType return ClrInternals.GetType(this); } #endregion #region IConvertibleToString Members public string ToString() { // let suppose that this is equivalent to the current implementation of Object.ToString return this.GetType().ToString(); } #endregion // this one is perhaps a little goofy, since it doesn't satisfy any interface // In order to be equivalent to the current Object.MemberwiseClone implementation, I've made this protected, // but we cannot have a protected method that implements an interface, so this throws a wrench into things. protected MyClassExampleA MemberwiseClone() { // let suppose that this is equivalent ot the current implementation of Object.MemberwiseClone return (MyClassExampleA)ClrInternals.MemberwiseClone(this); } // ** All of the above code is just a representation of the implicit semantics that the compiler/CLR applies to a class. Perhaps this code is not actually generated by the compiler for each class (that would be a lot of duplication!), but rather the CLR might handle this logic internally } // Ok, so now I'm implementing a general Stack class public class Stack { // what type should I use for the parameter? // I have five different interfaces to choose from that I know all classes implement, but which one should I pick? public void Push(type??? item) { // ... } // what type should I use for the return type? // I have five interfaces to choose from, but if I return one, // then my caller can't utilize the methods defined in the other interfaces without casting. // I know all classes implement all five interfaces, but is it possible that my Stack might also contain non-class objects that don't implement all interfaces? In that case it might be dangerous for the caller to cast the return value from one interface to another. public type??? Pop() { // ... } // In C++ I could have used void* or defined the Stack class as a template } // moving on... class StackUtilizer { // here I try to utilize the Stack class public void UseStack(Stack stack) { // what type should I use for the variable to hold the result of the Stack.Pop method? type??? item = stack.Pop(); // if I use IEquatable IEquatable item1 = stack.Pop(); IEquatable item2 = stack.Pop(); item1.Equals(item2); // then I can do this Type itemType = item1.GetType(); // but I can't do this string s = item1.ToString(); // nor can I do this // Ok, this calls for another interface that composes all of these other interfaces into one } } // let define a single interface that pulls all of these other interfaces together public interface IObject : IEquatable, IHashCodeGenerator, ITypeIdentifiable, IConvertibleToString, IMemberwiseCloneable { // no need to define any methods on this interface. The purpose of this interface is merely to consolidate all of these other basic interfaces together. } // now we change the compiler rule to say that all classes implicitly implement the IObject interface class MyClassExampleB : IObject { // ... <refer to MyClassExampleA for the implicit implementation of the interfaces> } // now let try implementing that Stack class again public class Stack { // I know that all classes implement the IObject interface, so it is an acceptable type to use as a parameter public void Push(IObject item) { // ... } // again, since all classes implement IObject, I can use it as the return type public IObject Pop() { // ... throw new NotImplementedException("This is an example. The implementation of this method is irrelevant."); } } class StackUtilizer { // here I try to utilize the Stack class public void UseStack(Stack stack) { // now I can just use IObject for my variables holding the return value of the Stack.Pop method IObject item = stack.Pop(); // if I use IObject IObject item1 = stack.Pop(); IObject item2 = stack.Pop(); item1.Equals(item2); // then I can do this Type itemType = item1.GetType(); // and I can do this string s = item1.ToString(); // and I can do this } } 

So, in the end, we still have an IObject interface, similar to the current System.Object class. An open question is how the / CLR handler will handle our rule that all classes implement the IObject interface. I can think of three possible approaches:

  • The compiler generates an implicit interface implementation for each class, which can cause a lot of duplication.
  • The CLR will handle these interface implementations in a special way, which does not require the compiler to generate code for each class.
  • We define a base class, call it Object (do we start to sound familiar?), Which implements the IObject interface, and we change the rule to say that all classes implicitly inherit from Object (this is exactly what we have today, but without interfaces).
+1
source share

All Articles