如何从基于给定类型的泛型方法 return new class 实例?

How to return new class instance from generic method based on given types?

我有两个 parent 类:ItemItemData。从第一个开始,我制作诸如 WeaponItem 之类的项目,从第二个开始,我制作诸如 WeaponData.
之类的相应数据 每个项目类型在其构造函数中采用相同类型的数据(例如:创建 WeaponItem 时需要 WeaponData)。

我有以下方法:

public static T CreateNewItem<T, DT>(ItemData data) where T : Item where DT : ItemData
{
    if (data == null) return null;
    if (data is DT dt)
    {
        //determine type of T
        Type itemType = typeof(T);
        if (itemType = typeof(WeaponItem))
        {
                //make a new weapon item...
                WeaponItem new_weapon = new WeaponItem(dt); //error!
                return new_weapon;
        }
        if (itemType = typeof(ArmorItem))
        {
                //make a new armor item...
        }
        //etc...
    }
    return null;
}

我这样称呼它:

CreateNewItem<WeaponItem, WeaponData>(data);

注意:dataItemData 类型或某种继承类型(例如 WeaponData)。

此方法需要两种类型:一种用于 Item,一种用于 ItemData。我有几件物品(武器、盔甲等...),我根据我提供的类型创建物品。我还想检查我使用的数据:data is DT dt 从我传递的数据中获取 WeaponData,如果转换失败则 null

当我尝试执行 WeaponItem new_weapon = new WeaponItem(dt); 时,出现以下错误:

Argument 1: cannot convert from 'DT' to 'WeaponData' [Assembly-CSharp]csharp(CS1503)

我试过像这样将 dt 转换为 WeaponDataWeaponItem new_weapon = new WeaponItem((WeaponData)dt);,但我得到了类似的错误

Cannot convert type 'DT' to 'WeaponData' [Assembly-CSharp]csharp(CS0030)

同样,使用 data 代替 dt 会产生错误。


是否可以不用每次都检查类型就可以解决这个问题?

你的设计对我来说有点反直觉,所以让我们从通用方法的一个极其简单的版本开始,然后从那里开始。您可以复制和编译此代码。

您也可以点击 this link 然后点击 运行 按钮。

我想说这里最大的优势是泛型方法变成了一行代码。您可以根据需要添加任意数量的项目,并且永远不会更改该方法。而您的实施变得越来越复杂。

代码:

public class ItemData
{
    public string ItemName { get; init; }
}

public class WeaponData : ItemData { }

public class Item
{
    public ItemData Data { get; init; }

    public Item(ItemData data)
    {
        Data = data;
    }
}

public class WeaponItem : Item  
{
    public WeaponItem(WeaponData data) : base(data) { }

    public override string ToString() => Data.ItemName;
}

public static T CreateNewItem<T, TD>(TD data) 
    where T : Item 
    where TD : ItemData
{
    return (T)Activator.CreateInstance(typeof(T), data);
}

static void Main(string[] args)
{
    var bestWeaponDataEver = new WeaponData() { ItemName = "Dragon Slayer" };
    var amazingWeapon = CreateNewItem<WeaponItem, WeaponData>(bestWeaponDataEver);
    Console.WriteLine(amazingWeapon);
}

输出:

Dragon Slayer

另一个很大的区别是您接受的是特定类型 ItemData,它应该是通用类型 DT。否则为什么 DT 甚至存在?这可能把你绊倒了。

public static T CreateNewItem<T, DT>(ItemData data) where T : Item where DT : ItemData

应该是这个

public static T CreateNewItem<T, DT>(DT data) where T : Item where DT : ItemData

请注意 WeaponItem 的构造函数只接受 WeaponData。因此,尽管使用了简单的通用方法,但您无法使用 ItemDataCakeData 或其他任何基础来创建武器。

如果您不确定如何扩展此评论,我会尽力提供进一步帮助。