【问题标题】:Generic with multiple classes具有多个类的泛型
【发布时间】:2013-07-23 15:19:17
【问题描述】:

我正在尝试创建这种通用方法来简化事情,但我想我搞砸了!你能帮忙解决我的问题吗?

这样编译:

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Supplier, new()
    where T1 : Employee, new()
    where T2 : SupplierDepartment, new()
    where T2 : EmployeeDepartment, new()
{
    T1 p = new T1();
    T2 r = new T2();
    //Code here for myEntity treatment
    return mystring;
}

虽然这不能编译:

protected void mybutton1_Click(object sender, EventArgs e)
{
   string mystring = ConcatenaText<Supplier, SupplierDepartment>(myEntity);
}

//This does not compile
protected void mybutton2_Click(object sender, EventArgs e)
{
   string mystring = ConcatenaText<Employee, EmployeeDepartment>(myEntity);
}

消息:类型 Supplier 不能用作泛型类型或方法 ConcatenateText(MyEntity myEntity) 中的类型参数 T1。没有从供应商到员工的隐式引用转换

这可以吗?我究竟做错了什么?可以改进吗?

编辑:

而 MyEntity 只是另一个类,以便在这个通用方法中处理它!它与类型 T 无关。它只是一个参数。但很明显,我不能这样做,使用 2 种这样的类型。我认为我可以分配一个或另一个,独立于我的初始化的 CLR 可以按照我的意愿做出反应。我会接受分享更多信息的答案。

【问题讨论】:

    标签: c# generics types parameters


    【解决方案1】:

    首先,尝试对泛型参数T1 设置两种类型约束的代码无法编译

    where T1 : Supplier, new()
    where T1 : Employee, new()
    

    出现以下错误:

    已经为类型参数“T1”指定了约束子句。类型参数的所有约束都必须在单个 where 子句中指定。

    正如 MSDN 文章所述,您只能对每个通用参数使用一个 where 约束(请参阅 http://msdn.microsoft.com/en-us/library/bb384067.aspx)。

    “有多个类型参数,每个类型参数使用一个where子句...”

    您也不能将多个类名放入一个“where”约束中。只有一个类名和几个接口。

    where T1 : Supplier, IContractor, IComparable, new()
    

    请记住,此约束规定您作为泛型参数T1 提供的实际类型必须是Supplier 类或Supplier 类本身的后继类型,并且它必须同时实现IContractor 和@ 987654330@接口。

    一旦你的方法接受MyEntity 对象并且你没有指定它与EmployeeSupplier 类的关系,我无法猜测这个MyEntity 类如何知道Employee 和@987654336 @classes 以及这种关系如何帮助你。

    我唯一能建议的是创建一个接口或一个基类,并从中继承你的两个类。这是我看到创建泛型方法的唯一充分理由。它可能看起来像这样:

    class Program
    {
        static void Main(string[] args)
        {
            Method1<Employee>();
            Method1<Supplier>();
        }
    
        private static void Method1<T1>()
            where T1 : IContractor, new()
        {
    
        }
    }
    
    public class Supplier : IContractor
    {
        string IContractor.Name
        {
            get{return "Supplier-Mufflier";}
        }
    }
    
    public class Employee : IContractor
    {
        string IContractor.Name
        {
            get{return "Employee-Merloyee";}
        }
    }
    
    public interface IContractor
    {
        string Name
        {
            get;
        }
    }
    

    如果您的类 Supplier 和 Employee 没有一些重要的共同点足以创建它们可以实现的通用接口,那么您不应该创建一个通用方法来处理它们。

    为每个此类类型创建一个重载方法。

    假设您有两个类:WifeWine。两者都具有Age 的属性并且也具有相同的类型。但是不要想为这些类创建一个通用接口IAged。类的本质和Age 的含义是如此不同,以至于永远不应该将它们统一起来。尽管如此,一些常见的逻辑可能会完美地为您服务。例如:

    private double AgeQualify(Wife someWife)
    {
        return 1 / (someWife.Age * someWife.Beachness);
    }
    
    private double AgeQualify(Wine someWine)
    {
        return someWine.Age / someWine.Sugar;
    }
    

    【讨论】:

    • 哎呀,当我写我的答案时,另外两个出现并说几乎相同
    • 很好的答案,但如果我没记错的话,你不能在一个班级上重载多个班级。所以在这个例子中接口和泛型是一个不错的选择。
    • @TarıkÖzgünGüner 不要混淆过载和覆盖。
    【解决方案2】:

    您要么需要制作单独的版本:

    private string ConcatenateText<T1, T2>(MyEntity myEntity) 
        where T1 : Supplier, new()
        where T2 : SupplierDepartment, new()  
    {
        T1 p = new T1();
        T2 r = new T2();
        return mystring;
    }
    
    private string ConcatenateText<T1, T2>(MyEntity myEntity) 
        where T1 : Employee, new()
        where T2 : EmployeeDepartment, new()
    {
        T1 p = new T1();
        T2 r = new T2();
        return mystring;
    }
    

    或者需要让它们共享一个基类:

    private string ConcatenateText<T1, T2>(MyEntity myEntity) 
        where T1 : EmployeeSuplierBase, new()
        where T2 : EmployeeSupplierDeparmentBase, new()
    {
        T1 p = new T1();
        T2 r = new T2();
        return mystring;
    }
    

    我更喜欢单独的版本,真的,因为他们不能用SupplierEmployeeDeparment 调用它(反之亦然)

    【讨论】:

    • 单独的版本不起作用。您已经定义了两个具有相同名称和相同参数的方法。不幸的是,更改返回类型并不能使其可重载。
    【解决方案3】:

    在这种情况下你真的不应该使用泛型。 只有两个选项。

    所以:

    string ConcatenateText(Supplier Entity) { ...code...} 
    string ConcatenateText(Employee Entity) { ...code...}  
    

    你可以做的是用一个集中了所有常用方法的基类将两者统一起来。

    假设供应商和员工都有Name

    class BaseClass
    {
        public string Name {get; set;}
    }
    
    class Employee : BaseClass
    {
        //emplyee stuff except name and other things already in base
    }
    
    class Supplier : BaseClass
    {
        //supplier stuff except name and other things already in base
    }
    

    然后,该方法采用BaseClass:

    private string ConcatenateText(BaseClass Entity) 
    { 
        //code
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-12-28
      • 2013-03-04
      • 2018-05-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多