C# NET是否能够在不使用类型对象的情况下正常工作?
我这样问是因为使用Object似乎是解决某些问题的简单方法,比如“我没有特定类型,所以使用Object”等等 这让我好奇的另一个原因是,我的一位同事告诉我,如果.NET是一个真正的面向对象平台,那么它就不必像object那样拥有一个包罗万象的类型 因此,如果.NET没有对象类型,有什么替代方法可以解决出现的问题,使其功能完全相同 还要注意的是,这不是bash.NET,因为我每天都在工作中使用它。我只是想知道更多C# NET是否能够在不使用类型对象的情况下正常工作?,c#,.net,types,base-class-library,type-systems,C#,.net,Types,Base Class Library,Type Systems,我这样问是因为使用Object似乎是解决某些问题的简单方法,比如“我没有特定类型,所以使用Object”等等 这让我好奇的另一个原因是,我的一位同事告诉我,如果.NET是一个真正的面向对象平台,那么它就不必像object那样拥有一个包罗万象的类型 因此,如果.NET没有对象类型,有什么替代方法可以解决出现的问题,使其功能完全相同 还要注意的是,这不是bash.NET,因为我每天都在工作中使用它。我只是想知道更多 编辑:我记得的另一个注意事项是因为类型对象存在,它的效果会波及整个.NET。像IEn
编辑:我记得的另一个注意事项是因为类型对象存在,它的效果会波及整个.NET。像IEnumerable一样存在,但也存在IEnumerable。在许多情况下,您必须实现事物的泛型和非泛型版本,等等。在强类型框架中,对象必须从某个地方开始。
类型
对象
不是为了提供一个“简单”的全套铸造选项,也不是为了强制您铸造到最低公分母。它为一个对象提供了绝对最一般的情况——一个参考比较的基础和一个方便的ToString()
方法,以及其他一些方法。我想说object
解决的问题不是“我没有特定的类型,所以使用object”,而是“我真的不在乎这是什么类型;我只需要知道它是一个对象
“它很方便,不仅可以用作“泛型”类型,还可以用于反射、垃圾收集等
其他语言(C++)可以不使用,但我不想说这会使这些语言更面向对象。是的,对象类型可能会被误用,但它为.NET世界提供了开创性的功能(最重要的是IMO是GetType())。因此,如果有问题,这与对象类型无关
替代方法很多,包括泛型和OOP实践,如接口…请记住,继承表示“is-a”关系。在.NET中的每个类都是a(n)“反对。它们都有一个
ToString
方法。它们都有一个类型,您可以通过GetType
访问该类型。这种关系以及由此产生的功能共享是面向对象编程的基础。如果对象派生层次结构没有一个统一的头,那么如果不借助动态类型,就不可能测试任意两个……嗯……事物之间的相等性
除此之外,我怀疑对象的功能也可以通过单独的接口(IEqualable和IConvertableToString)来处理。另一方面,对象的虚拟方法有时非常方便,尤其是ToString,IDE或调试器在显示程序状态时可以使用它。这确实是一个实用的设计。你的朋友可能使用动态语言(如ruby或python),对吗 有很多人认为强类型语言应该被称为“面向类”而不是“面向对象”,因为所有可能的行为和多态性都需要在类定义中提前完成。当您的方法接受任何内容时,任何检查都是基于对象功能而不是其类来完成的,您可以说这是一种更面向对象的方法
我在这个论点上有点矛盾。编程界有一种愚蠢的信念,即无论出现什么问题或需求,OO都绝对是好的。正因为如此,人们往往试图通过说“某某不是面向对象的”来赢得争论,而且因为面向对象是好的同义词,所以他们赢了。尽管我认为使用静态语言是一件痛苦的事情,但我认为称它们为非OO是一种不真诚的表达观点的方式。另一方面,任何能让程序员走出自己的舒适区,学会一种新的做事方式(如果没有其他原因,那就是赢得争论)的事情都不会完全是坏事。正如我所说,矛盾。:) 我对这方面的知识并不特别渊博,但从我的角度来看,允许人们在事先不知道如何使用这些组件的情况下构建多态组件是很有用的。我这是什么意思?让我试着解释一下 让我们以.NET framework的
ArrayList
类为例。在引入泛型之前,这是原始框架的一部分。ArrayList
类的作者试图提供一个有用的动态列表实现,但是他们无法知道哪些类型的对象将被插入到列表中。他们使用对象类型来表示列表中的项目,因为它允许将任何类型的类添加到列表中。例如:
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];
// ...
}
ArrayList people=new ArrayList();
添加(新医生());
添加(新律师());
添加(新的PetDetective());
people.Add(新法拉利());//哎呀!
// ...
for(int i=0;i
现在,如果这是您自己的应用程序,并且您知道您的医生
、律师
、和宠物侦探
类都是从一个普通的人
基类派生出来的,那么从理论上讲,基于Person
类而不是对象
类构建自己的链表实现。然而,当您已经有了一个已构建和测试的ArrayList
类时,这是一个非常多的额外工作,几乎没有什么好处。如果您确实想使它特定于您的Person
基类,那么您可以始终为该类创建一个包装类ArrayList
// let's 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's 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's 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's suppose that this is equivalent to the current implementation of Object.GetHashCode
return ClrInternals.GetHashCode(this);
}
#endregion
#region ITypeIdentifiable Members
public Type GetType()
{
// let's suppose that this is equivalent to the current implementation of Object.GetType
return ClrInternals.GetType(this);
}
#endregion
#region IConvertibleToString Members
public string ToString()
{
// let's 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's 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's 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's 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
}
}