在C#中创建通用方法

4

我有以下结构:

public enum MyTypes
{
    Type1 = 1, 
    Type2 = 2,
    Type3 = 3
}

public abstract class class1
{
   int id;
   string name;
   MyType type;
}

public class class2 : class1
{

}


public class class3 : class1
{

}

public class class4 : class1
{

}

现在我想要做的是创建一个通用方法,我想要给它一个对象类型,比如说类3,它将从类3创建一个对象并定义它的变量,然后返回该对象以便将其添加到类1的列表中。

就像这样

private class1 myFunction (MyType t , int id , string name)
{
    T obj = new T();
    obj.type = t ;
    obj.id = id ;
    obj.name = name;
    return obj;
}

如何创建这个通用方法?

请尽快帮助我。

提前感谢。


1
如果您想从它们实例化对象,那么这些派生类(class2 - class4)不能是抽象的。 - Dialecticus
... 为什么要用枚举?如果你出于某种原因确实需要一个反映类型的枚举,那么就在具体类型的构造函数中设置它(或者更好的方法是将其作为计算属性返回)。 - SoftMemes
是的,我很抱歉打错了,你是正确的。 - Amira Elsayed Ismail
枚举将帮助我决定要使用的对象类型,另外类型来自另一个类。 - Amira Elsayed Ismail
如果您确实需要使用枚举来指定类型,请参见下面提供的建议工厂模式的变体。然而,如果这是您想要的,它实际上并不是.NET中通用函数的意义。 - SoftMemes
5个回答

15

正如丹尼·陈在他的回答中所说,您需要稍微修改类定义才能使其正常工作,然后您可以执行以下操作:

public T myFunction<T>(int id, string name) where T : class1, new()
{
    T obj = new T();
    obj.id = id;
    obj.name = name;
    return obj;
}

这个通用方法需要类型参数 T 派生自 class1,并且还需要一个无参构造函数——这就是 where T : class1, new() 的含义。
由于 idname 属性是通过基类 class1 定义的,因此您可以将它们设置为通过其参数传递给 myFunction 的任何内容。
关于 class1 还有一些需要注意的事项:
  • 考虑将 class1 设计为接口,而不是抽象类,因为它不包含任何功能。
  • 如果您真的想要访问它们,idnametype 需要是公共的。
  • 通常,字段并不会实际公开为 public。考虑使用属性代替。

2
不行,因为所有这些类都是抽象的(无法实例化)。我们不能创建抽象类的实例。

不,那是我的错误,我已经修复了。只有父类是抽象的,其他类继承自它。 - Amira Elsayed Ismail
我认为你的意思是“无法实例化”,而不是“继承自”。 - Tamás Szelei

0

如果我理解正确,您正在询问如何创建工厂模式。这正是该模式的设计目的:指定您想要的对象类型,它会将其返回给您。

或者,您可以在函数中使用类型开关。

private class1 myFunction (MyType t , int id , string name)
{
    class1 obj;
    switch(t)
    {
        case MyTypes.Type1:
           obj = new Class1();
        ...
    }

    obj.type = t ;
    obj.id = id ;
    obj.name = name;
    return obj;
}

第三种方法是使用泛型。
private T myFunction<T>(MyType t , int id , string name) where T : class1, new()
{
    T obj = new T();
    obj.type = t ;
    obj.id = id ;
    obj.name = name;
    return obj;
}

你可以这样调用:

var obj = myFunction<Class3>(MyTypes.Type3, 5, "some name");

0
你要找的基本上是抽象工厂设计模式。 http://en.wikipedia.org/wiki/Abstract_factory_pattern 做类似以下的事情。
private class1 createSpecializedType<T>(MyType t, int id, string name) where T: class1, new()
{
    T obj = new T();
    obj.type = t ;
    obj.id = id ;
    obj.name = name;
    return obj;
}

public class1 createMyType(MyType t, int id, string name)
{
    switch(t)
    {
         case Type1:
              return this.createSpecializedType<class2>(t, id, name);
         case Type2:
              return this.createSpecializedType<class3>(t, id, name);
         case Type3:
              return this.createSpecializedType<class4>(t, id, name);
    }
}

代码未经测试,应被视为伪代码。

这将允许您调用createMyType,并通过参数确定您想要的类,并返回正确的对象。

附注:当然,这些类是抽象的,不能被实例化。但我怀疑这是复制/重写代码时引入的错误。


1
我认为你在T上缺少了new()类型约束。 - stakx - no longer contributing

0
如果我理解正确,MyTypes 和类的实际类型表达的是相同的事情。在这种情况下,你需要有某种从你的MyTypes到实际类的映射,例如:
static Dictionary<MyTypes, Type> typeMapping = new Dictionary<MyTypes, Type>
  {
    { MyTypes.Type1, typeof(class2) },
    { MyTypes.Type2, typeof(class3) },
    { MyTypes.Type2, typeof(class4) },
  };

然后,您可以使用反射来创建指定类型的实例:

private class1 myFunction(MyType t, int id, string name)
{
    class1 obj = (class1)typeMapping[t].GetConstructor(Type.EmptyTypes).Invoke(null);
    obj.type = t ;
    obj.id = id ;
    obj.name = name;
    return obj;
}

如果在编译时已知所有类型,使用 switch 会更好。如果需要在运行时操作映射,也可以使用从枚举到 Action<class1> 的字典来避免反射。最后,如果确实需要反射,Activator.CreateInstance 是一个更好的选择。=) - SoftMemes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接