如何从C#中的方法返回通用对象

时间:2011-02-14 07:31:17

标签: c# .net

我遇到与this问题类似的问题,我只是在学习泛型,所以想要一个实用的解决方案,我的方法返回的不仅仅是intdouble

我有一个函数可以根据用户输入返回一个对象(来自一组彼此无关的已知类)。

例如,如果我有以下两个类

public class A
{
}

并且

public class B
{
}

我的方法是:

public Object getObject(int objType)
{
    //return appropriate object based on objType (1==A, 2==B);
}

我可以在我的代码中使用if (getObject(int objType) is A)这样的语句,但这需要很多if语句,这不是一个好的解决方案(恕我直言)。

所以我正在寻找更好的设计解决方案来解决这个问题。有什么建议吗?

修改

我需要使用返回的对象一段时间,可能还需要将其传递给其他方法或返回它的引用。所以期待一些移动到那个对象。在建议解决这个问题的方法时,请记住这一点。

8 个答案:

答案 0 :(得分:1)

开关/箱体怎么办?

public Object getObject(int objType) 
{
    switch( objType )
    {
      case 1: return new A();
      case 2: return new B();
    }
}

请注意,这与generics一样 nothing

修改

阅读完评论后,我发现这根本不是你需要的。根据新的信息,我看到只有两种方法可以(稍微)得到你需要的东西。

  1. 如果可能,请创建AB都继承的基类(在这种情况下让我们称之为C),并使getObject方法返回C的对象。
  2. 使方法通用public T getObject<T>()。这意味着调用者必须将对象类型而不是1或2发送到getObject方法中,但至少他知道他将得到什么作为回报。
  3. 只要该方法返回object,并且仅使用int的参数来决定要创建哪种类型的对象,就无法找到您获得的对象类型返回检查对象本身,如果有很多类型的对象可以返回,那么这种代码很快就会变得混乱。

答案 1 :(得分:1)

根据某些输入声音构建不同类型的对象,就像使用Factory设计模式一样。

编辑:如果您希望调用者不检查对象类型,那么Factory模式正在成为可行的选项,因为它利用了polimorphism。将实际对象返回到基类类型的变量中,当您调用方法时,将根据实际对象类型运行正确的代码。

如果你的类型是不相关的,那么看看你是否可以让它们共享一个基类是值得的,因为使用polimorphism比解决问题更能解决问题。

答案 2 :(得分:0)

如果我有一个必须返回一个对象的类,并且我必须从一个特殊类型获取它,我通常在一个像Dictionary<Type, Func<Type>>这样的字典中有一组工厂函数(可能有{{1}这样的参数然后我编写这些函数并将它们放入字典中。然后你可以轻松地从中获取正确的对象。

另一种方法(如果您可以访问对象的源代码并且它们有共享内容),您可以向它们添加一个接口,然后创建一个Func<P1, P2, ..., Type>。如果您的对象的顺序正确(如果您想使用List<MyInterface>),则只需拨打int objType即可获得正确的对象。

答案 3 :(得分:0)

如果您只想获取提供程序类的新实例,则可以使用此函数。

 public T GetObject<T>() where T : new()
 {
        return new T();
 }

无需提及objectType

答案 4 :(得分:0)

仅供参考,您正在实施一种Factory pattern

通常,在处理改变类型行为的函数时,只有两种方法可以避免切换:

  • 利用多态性
  • 使用从源值到目标类型的字典映射(与交换机几乎相同 - 代码量相同,可维护性问题相同)

在您的示例中,对工厂的输入是完全不相关的类型,因此您不能使用多态。

如果您可以要求用户传入一些自定义类型,那么您可以利用工厂中的多态性:

public class Selection
{
    public abstract object Select();
}

public class SelectionA : Selection
{
    public override object Select()
    {
        return new A();
    }
}

public class SelectionB : Selection
{
    public override object Select()
    {
        return new B();
    }
}

// ...

public Object getObject(Selection selection)
{
    return selection.Select();
}

如果AB彼此相似,那么您真的应该为它们创建一个公共基类,或者如果您无法触及该代码,请使用Adapter模式,使另外3个类,具有正确的层次结构。

如果它们彼此不相似,并且您必须int作为工厂方法的输入,那么交换机,if / else-if链或字典是您唯一的选择:

public Object getObject(int objType)
{
    switch(objType)
    {
        // etc
    }
}

或者

public Object getObject(int objType)
{
    if(objType == 1)
        return new A();
    // etc
}

或者

public Object getObject(int objType)
{
    var mapping = new Dictionary<int, Type>()
    {
        { 1, typeof(A) },
        { 2, typeof(B) },
    };

    // use reflections to instantiate based on type
    if(!mapping.ContainsKey(objType))
        throw new ArgumentException("Invalid type ID specified", "objType");

    System.Activator.CreateInstance(mapping[objType]);
}

答案 5 :(得分:0)

你的方法有什么不好 - 无论如何客户端代码应该知道这个方法返回了什么类型的对象(没有多态,所以你不能返回基类类型的对象):

A a = (A)getObject(1)
B b = (B)getObject(2)

BTW最好使用Enum来定义对象类型,而不是int。

因此,当客户端知道将返回什么方法时,为什么不为客户端创建两个单独的方法?

A a = getA()
B b = getB()

如果这些对象具有相同的目的,最好在这里使用继承形式基类:

C c = getObject(ObjectType.A);

答案 6 :(得分:0)

我会将Adeel的答案与Dictionary结合使用来存储类型与int的组合。由于您使用整数来识别类型,因此无论如何都需要在它们之间进行映射。

 Dictionary<int, Type> dictionary = new Dictionary<int, Type>();
 //fill the Dictionary with all int/Type-combinations

{
 int objectType;
 Type type = dictionary[objectType];
 var genericMethodInfo = this.GetType().GetMethod("GetObject").MakeGenericMethod(type);
 object newObject = genericMethodInfo.Invoke(this, null);
 var objectInCorrectType = Convert.ChangeType(newObject, type);
}    

public T GetObject<T>() where T : new()
{
 return new T();
}

答案 7 :(得分:0)

你真的必须使用if语句。我可能会这样做:

var result = getObject(...);
if (result is A) { ... }
else if (result is B) { ... }

但是,你有一个非常奇怪的方法叫做getObejct()。因为,你必须传递一个int来获得结果类型;这意味着您已经知道所需的对象类型。所以,当你想要A做“var a =(A)getObject(1)”时,你想要B做“var b =(b)getObject(2)”。