我是PHP程序员已经有一段时间了。两天前,我去了一个面试,他们给了我一个在ASP.NET(C#)做的分配。我真的想摆脱php领域的势力,学习一种可以挑战我的体面语言。所以,我有一个问题
是否必须在运行时实例化所有实例?在php中,我可以做这样的事情......
class SomeObject {}
$objString = "SomeObject";
$objInstance = new $objString();
我不能在C#中这样做,可能因为它是一种编译语言。在C#中,我是否必须创建一个将实例化对象的Factory模式。这也意味着如果我必须在该Factory中实例化10个对象,那么将会有10个if
语句很难看。
我找到了Activator对象及其Activator::createInstance()
方法,但我无法使其工作。还有反思,但这两者(我都知道)会对性能产生影响。
那么,有没有办法动态创建对象,或者可能是在C#中,我可以立即创建我的程序将使用的所有对象,这真的很诱人?
修改
好的,所以让我们说我有5个不同场合使用过的对象。我运行程序,程序评估它需要其中一个对象并实例化它。其他四个从未实例化。我关闭了程序。
第二次,我使用不同的参数运行程序,并创建了这5个对象中的2个,其他三个从未出现过。
这在PHP中很容易。让我们把Activator和其他工具放在一边,当我知道可能只使用其中一个对象时,在C#世界中创建所有5个对象是不错的做法?
答案 0 :(得分:5)
是的,您可以在C#中动态创建对象。但不像PHP那么容易。
如您所见,有Activator
。正确使用它可以正常工作。 :)还有直接反射(Activator
也基于反射)。天真地使用时两者都很慢。
使用Expression
类型,可以缓存用于实例化对象的逻辑。第一次它仍然很慢,但是如果你希望重复创建相同类型的对象,这种方法效果很好(如果你不这样做,那么通过Activator
它很慢的事实并不重要: ))。
也就是说,大多数情况下,您不需要像示例中那样动态创建对象。 C#中强大的编译时类型检查应该被利用,而不是避免使用。编写实例化在编译时已知类型的对象的代码是最有效的,而且大多数是类型安全的。
对于那些需要动态行为的相对较少的时间,这是可能的。
答案 1 :(得分:4)
我不知道我的问题是否错误,但在C#中创建给定班级SomeObject
的对象就像以下一样简单:
var obj = new SomeObject();
使用Activator
- 类它应该看起来......喜欢以下之一
var obj2 = Activator.CreateInstance(typeof(SomeObject));
var obj3 = Activator.CreateInstance<SomeObject>();`
var someObjType = Type.GetType("SomeObject"); // if you have to use a string
var obj4 = Activator.CreateInstance(someObjType);
请注意,在大多数情况下,使用Activator
- 类来实例化对象并不是必需的。如果您在编译时知道类的Type
,那么第一个示例是标准方法。
<强>更新强>
关于你的更新,因为我不知道细节,我想到的是懒惰的实例。由于所有内容(包括应用程序的入口点都是C#中的对象),您可以使用带有支持字段的属性来解决问题,如下例所示
class Program
{
// backing fields
private SomeObject obj1;
private SomeObject obj2;
private SomeObject obj3;
private SomeObject obj4;
private SomeObject obj5;
// this way, obj1 only gets instanciated when needed
public SomeObject Obj1
{
get
{
if (obj1 == null)
{
obj1 = new SomeObject();
}
return obj1;
}
}
// same for the other objects
[...]
}
我担心您对象的内存使用情况,我建议您了解如何正确实施IDisposable
更新2
为了提供@Mad Sorcerer评论中推荐的可能性,您可以使用Lazy
- 类来支持字段,这需要您付出一些努力,效果与之前的更新完全相同。
class Program
{
// Lazy backing fields
private Lazy<SomeObject> obj1 = new Lazy<SomeObject>();
private Lazy<SomeObject> obj2 = new Lazy<SomeObject>();
private Lazy<SomeObject> obj3 = new Lazy<SomeObject>();
private Lazy<SomeObject> obj4 = new Lazy<SomeObject>();
private Lazy<SomeObject> obj5 = new Lazy<SomeObject>();
// this way, obj1 only gets instanciated when needed
public SomeObject Obj1
{
get { return obj1.Value; }
}
// same for the other objects
[...]
}
答案 2 :(得分:2)
那么PHP代码......你选择用它的名字作为字符串来实例化哪个类?
您需要先查找类型,然后使用Activator进行实例化。
Type classType = Type.GetType("SomeObject");
object instance = Activator.CreateInstance(classType);
你可以查看它的构造函数,然后使用看起来更像是
的反射来调用它Type classType = Type.GetType("SomeObject");
var ctorInfo = classType.GetConstructor(Type.EmptyTypes);
object instance = ctorInfo.Invoke(new object[] {});
并且您可以将构造函数缓存为委托,从而消除查找内容所带来的性能损失#
请注意Type.GetType
有一些问题。如果 SomeObject 位于System
命名空间中,则上述代码将起作用。您可能需要添加命名空间,类和某些时候的程序集。总之,最安全的是使用AssemblyQualifiedName。
答案 3 :(得分:1)
有几种方法可以在C#中创建一个类的实例。
通常的方法是使用new
:
MyType myInstance = new MyType();
为了动态创建对象,例如,基于它们的名称,Activator.Createinstance()
有效,但您必须知道定义该类的程序集,以便您可以正确地创建该实例。
然而,特别是如果你刚刚开始,我也不会为进入这个而烦恼 C#是一种静态类型语言,这意味着在编译期间会对类型进行解析。
最重要的是,考虑到IDE,Visual Studio将极大地帮助您,因为它可以扫描项目中的文件并知道您在代码中键入的每个成员的类型。
静态类型语言有助于避免纯动态语言中出现的确切类型的问题:它们会迫使您保持连贯,但要求您在声明中明确(尽管C#,{{ 1}}关键字,可以帮助避免通常需要的冗长)。
因此,重点是确保在申请中声明所需的所有类型。
如果您需要一个特定的类成员来接受来自多个其他类的数据,您可以使用inheritance,创建一个其他人将继承某些行为的基类,或者使用Interfaces来描述常见的成员到各种类型。每个都有advantages and drawbacks。
如果您正在使用C#,只是尝试一下,我建议您LINQpad。它可以帮助你在学习的同时进行实验。
我也会远离任何不规范的东西:在你试图做运行时的事情之前,先了解惯用的C#。
您可以探索的一个区域是var
类型。它不像你对真正动态的语言所期望的那样灵活,但它是处理类型不确定性的一种方式。
但是它有一个性能上的缺点,如果你想从Visual Studio中的Intellisense中受益并希望受益于IDE和编译器可以为你提供的常规类型检查,那么应该避免它。