C# 泛型方法和动态类型问题

3

我有一个通用方法,声明如下:

public void Duplicate<EntityType>() { ... }

因此,通常使用它只需要这样做:
myObject.Duplicate<int>()

但是,这里我想通过一个变量传递类型,但是它不起作用,以下是我的尝试方法:

Type myType = anObject.GetType();
myObject.Duplicate<myType>();

有人能帮我吗?

提前感谢。

4个回答

12

你必须使用反射,基本上是这样的:

MethodInfo method = typeof(...).GetMethod("Duplicate");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(myObject, null);

1
总有一天我会听从你的建议,先发布再修改。又一次被打了冷枪,因为要检查方法名。 :) +1 - Harry Steinhilber
应该可以解决问题,我会测试一下。 - Karnalta
嘿,@Jon,我知道你的答案大约是5年前的,也许MethodInfo.Invoke方法曾经有一个重载(如果不是唯一的),它只需要一个参数,但现在情况已经不同了。如果要调用的方法不需要任何参数,我们需要至少传递null。还有另一种情况,可能会有Duplicate方法的重载,这将抛出AmbiguousMatchException异常。我相信你知道这个,但我还是想加上我的两分钱。 - Mikayil Abdullayev
@MikayilAbdullayev:添加了null参数。 - Jon Skeet

4

如果您将类型设置为变量,则很难为通用方法找到一个好的候选项,特别是当您的方法不返回任何内容时。

使用以下代码会更好:

public void Duplicate(Type entityType) { ... }

然后你的代码变成了:
Type myType = anObject.GetType();
myObject.Duplicate(myType);

您可以使用Jon Skeet(正确的)答案通过反射调用方法,但我看不出您从将此方法变成通用方法中获得了什么好处。
泛型的目的是为了保留类型 - 这样您就不必对值类型进行装箱/拆箱等操作。
然而,您的重复方法没有返回(它是一个void),也没有输入参数。基本上唯一的输入是类型参数。这意味着在您的通用方法内部,您可能正在执行像以下内容的操作:
public void Duplicate<EntityType>() 
{
 ...
 Type inputType = typeof(EntityType); 
 ...
}

如果这样的话,将EntityType作为一个泛型类型参数而不是一个常规输入参数并没有什么好处,反而会在您不知道输入类型时增加笨拙和缓慢的反射需求。


0

Duplicate() 函数的确切功能还不太清楚,但以下示例在您想要传递给 Duplicate() 的类型为类或整数时有效。

本质上,不要传入类型,而是传入一个示例对象。此测试方法说明了调用(一个方法中的两个测试)。

    [TestMethod]
    public void TestMethod1()
    {
        var myObject = new AnObject { AString = "someString" };

        var myOtherObject = new AnotherObject();
        var newObject = myObject.Duplicate(myOtherObject);
        Assert.IsTrue(newObject.AString=="someString");

        var newObject2 = myObject.Duplicate(1);
        Assert.IsTrue(newObject2 is Int32);
    }

Duplicate() 方法有一个与示例对象相关联的类型参数,但不需要使用给定的类型作为参数调用它,它会从示例对象中推断出来。

这是一个带有 Duplicate() 方法的类:

public class AnObject
{
    public string AString { get; set; }

    public T Duplicate<T>(T exampleObject)
        where T: new()
    {
        var newInstance = (T)Activator.CreateInstance<T>();

        // do some stuff here to newInstance based on this AnObject
        if (typeof (T) == typeof (AnotherObject))
        {
            var another = newInstance as AnotherObject;
            if(another!=null)
                another.AString = this.AString;
        }

        return newInstance;
    }
}

为了完整地呈现,这是AnotherObject类。
public class AnotherObject
{
    public string AString { get; set; }
}

当传入的类型是值类型例如 int 时,这段代码可能在 Duplicate() 方法内部存在一些问题。具体取决于您想让 Duplicate() 对 int 做什么操作(您可能需要将其作为可空 int 传递)。

对于引用类型(类),它能够很好地运行。


实际上,如果你正在走通用路线,我认为Keith的回答比我的更好。不需要任何示例类型。我假设它可以工作,并且你不需要返回值。 - Ackroydd
我假设Duplicate()函数旨在返回传入类型的克隆,但是您的问题表明没有返回值。 - Ackroydd

0
你可以使用一个以类型为参数的标准方法:
myobject.Duplicate(myType);

或者你可以尝试使用反射,类似于:

System.Reflection.MethodInfo mi = typeof(TypeOfMyObject).GetMethod("Duplicate<>");
MethodInfo constructedMethodInfo = mi.MakeGenericMethod(new type[] {myType});
constructedMethodInfo.Invoke(myObject, new object[] {});

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