2011-09-08 93 views
2

我必须根据构造函数的参数构建一个特殊的类行为。如果Foo绘画应该变成永久绿色,如果它是用绿色铅笔构建(绘制)的。 如果有铅笔在哪里使用,Foo应该是透明的...构造函数的优先顺序

现在,看下面的代码。是否有可能修改构造函数“查看”传入参数对象的实际类型的“输出”? (其实他们都是 “对象” S):

class Program 
{ 
    static void Main(string[] args) 
    { 
     object[] objs = { new IndexOutOfRangeException(), MyEnum.Beta, 45, new AssemblyName(), new { Name = "a" } }; 

     for (int i = 0; i < objs.Length; i++) 
     { 
      Console.WriteLine("{0} => {1} ", i, objs[i]); 
     } 
     Console.WriteLine("=========================== "); 
     for (int i = 0; i < objs.Length; i++) 
     { 
      Foo myFoo = new Foo(objs[i]); 
      Console.WriteLine("{0} => {1}", i, myFoo); 
     } 
    } 
} 

public class Foo 
{ 
    object value; 
    string typeName; 

    public Foo(object obj) 
    { 
     value = obj; 
     typeName = "object"; 
    } 

    public Foo(MyEnum enm) 
    { 
     value = enm; 
     typeName = "MyEnum"; 
    } 

    public Foo(int myInt) 
    { 
     value = myInt; 
     typeName = "int"; 
    } 

    public Foo(Exception ex) 
    { 
     value = ex; 
     typeName = "exception"; 
    } 

    public override string ToString() 
    { 
     return string.Format("FOO (object = '{0}'; type = '{1}')", value, typeName); 
    } 
} 

public enum MyEnum 
{ 
    Alpha, 
    Beta 
} 

输出

0 => System.IndexOutOfRangeException: Index was outside the bounds of the array. 
1 => Beta 
2 => 45 
3 => 
4 => { Name = a } 

=========================== 

0 => FOO (object = 'System.IndexOutOfRangeException: Index was outside the bound 
s of the array.'; type = 'object') 
1 => FOO (object = 'Beta'; type = 'object') 
2 => FOO (object = '45'; type = 'object') 
3 => FOO (object = ''; type = 'object') 
4 => FOO (object = '{ Name = a }'; type = 'object') 

编辑:

正如看到一些答案,我想强调的是,是不是正确的字符串显示在“类型”变量中,例如使用value.GetType(),但是关于“输入”正确的构造函数是问题。

换句话说,为什么编译器没有检测到正确的类型并将其“重定向”到正确的构造函数?

编辑2:

正如应答者提到的,“办法”来构造器“内置”在编译的时候,而不是在运行时。说喜欢他的

将输出

MyEnum en = MyEnum.Beta; 
Console.WriteLine("Enum example: obj:{0} Foo:{1}", en, new Foo(en)); 
“好”输出代码:显然,像提出

Enum example: obj:Beta Foo:FOO (object = 'Beta'; type = 'MyEnum') 

所以...任何方式“绕过”这种行为,但在构造函数中运行时的检测,里德科普塞...?!

+0

编译器无法检测到类型,因为直到运行时才知道类型。因此它不能确定正确的cctor。 –

+0

@David Neale:谢谢。我需要一个解决方法来“绕过”。 ) – serhio

+0

使用反射('GetType()')获取类型名称的建议有什么问题?当你到达运行时,那是你可以做到这一点的唯一方法。否则 - 为什么你循环这些对象?有必要吗? –

回答

3

为什么编译器没有检测到正确的类型并将它“重定向”到正确的构造函数?

这是因为你传递的对象为System.Object。 (object[] objs = { n...)在编译时选择构造函数,而不是在运行时。编译器可以看到所用变量的声明,并用于检查适当的类型。

正如你在另一则留言中提到:

好吧,如果我有对象的大阵,不知道的,先验的类型?

这正是编译器这样工作的原因。它在编译时不知道你想要哪个构造函数,并且因为你有一个可以工作的构造函数,所以它被选中。

如果要单独处理这些特定类型,但仍然将该对象构造为System.Object,则必须为构造函数内部的对象添加检查,并分别处理特定情况。但这不是最易维护的代码,如果你这样做的话。

public Foo(object obj) 
{ 
    value = obj; 
    typeName = "object"; 

    // Change typeName if appropriate 
    if (obj != null) 
    { 
     if (obj is MyEnum) 
      typeName = "MyEnum"; 
     else if (obj is int) 
      typeName = "int"; 
     else if (obj is Exception) 
      typeName = "exception"; 
    } 
} 

编辑:

鉴于这种情况,在你真正的代码,构造很可能会做更多的工作,我会考虑一个工厂方法来处理这个问题。这将允许你使用类似的方法如上,但留下的类型安全构造到位:

// I'd make the object constructor private, to prevent accidental usage: 
private Foo(object obj) { ... 

public static Foo CreateAppropriateFoo(object obj) 
{ 
    if (obj == null) 
     return new Foo(obj); // Use object constructor 
    else 
    {    
     if (obj is MyEnum) 
      return new Foo((MyEnum)obj); 
     else if (obj is int) 
      return new Foo((int)obj); 
     else if (obj is Exception) 
      return new Foo((Exception)obj); 
    } 
} 

这,至少,防止构造逻辑的重复,以及使得它多一点明显在运行时有一些逻辑发生。

+0

所以,你建议我将所有特定的构造函数替换为一个大的和常见的......我想我可以避免它... – serhio

+0

@serhio:我不一定会替换它们,但如果你想为了能够传递一个'Object'并确定类型,你需要在运行时进行检查。由于我上面提到的原因,编译器不会处理这个问题。留下其他的构造函数是好的,因为它允许编译器在传递实际类型时正确地计算出它(即:异常,声明为Exception或子类) –

+0

是的,但我会以这种方式复制代码。由于(错误地)提出Devendra D.查万,我不能,不幸的是,在另一个使用构造函数,以便不重复代码... – serhio

0

我想你可以通过删除接受对象参数的ctor(然后所有东西都应该正确绑定到正确的构造函数)或者通过将参数强制转换为适当的类型来得到你想要的东西,例如:

var myFoo = new Foo(objs[0] as Exception); 

很可能将ctor与Exception参数一起使用。

编辑:你的问题:为什么编译器没有检测到正确的类型并将其“重定向”到正确的构造函数?

我的回答:因为你传递一个对象数组的成员,所以编译器是权利在处理实际的对象实例作为对象。

它就像catch块一样,必须从最普通的序列到更一般的序列,你有一个通用的捕获器让你的ctor接受一个对象,并且你不应该感到惊讶的是从一个对象数组编译器使用最合适的候选。这就是为什么我建议你在调用ctor时进行强制转换,这样你可以明确地告诉你要将objs [0]强制转换为Exception对象,否则编译器会将其视为对象。

+0

好的,如果我有大量的对象,并且不知道,*先验*他们的类型? – serhio

+0

你正在与风搏斗。没有赢家那里... –