如何使方法采用2种不同的类型

时间:2010-09-09 20:51:13

标签: c# generics overloading

我知道这可能是一个非常简单的问题,但我目前正在做脑屁。我正在尝试创建一个可以采用2种自定义类型之一的方法。基本上这个方法的主体对于两种类型都是相同的,因为它们都具有Name属性(我在Name属性上进行比较以用于排序)。我该怎么做?

我的第一个想法是用两种类型作为参数重载方法:

int Compare(Type1 first, Type1 second)
int Compare (Type2 first, Type2 second)

但这些方法的主体最终是相同的,因此它似乎是一种浪费。

我的下一个想法是使用泛型,但这似乎并不正确,因为我并没有真正使它成为通用的,因为它只能用于2种特定类型。

澄清:“自定义”类型实际上不是我的自定义类型。我的意思是他们不是内置类型。我无法控制这些类型或继承层次结构中的内容。他们碰巧都有Name属性。

7 个答案:

答案 0 :(得分:8)

奇怪的是到目前为止还没有人发布我认为是明显的选择:将名称作为比较的参数。使调用者从对象中获取name属性。如果需要使用的所有方法都是名称,那么为什么要传递对象的其余部分呢?

如果你需要抽象出“我可以从这个东西中得到一个名字”的概念,那么就这样做:

示例:

int Compare(string name1, string name2) { ... whatever ... }
int Compare<T>(T t1, T t2, Func<T, string> getName)
{
    return Compare(getName(t1), getName(t2));
}

现在你可以说:

Compare(car1, car2, c=>c.Name);
Compare(employee1, employee2, e=>e.Name);

等等。

答案 1 :(得分:7)

如果两种类型派生自相同的基础或使用相同的接口,并且没有其他类使用基础和/或接口,则通用仍然是一种选择。

int Compare<T>(T first, T second) where T : IHasName

除此之外,有两个重载是要走的路。

注意:如果你有.NET 4,你可以使它成为运行时事物并使方法动态化。

int Compare(dynamic first, dynamic second)

在这种情况下,你抛出的任何内容都会编译,但如果Name属性不存在,它会在运行时爆炸。

就个人而言,如果我无法修改类型以使用通用接口,那么我会使用重载并获得编译时的安全性。

答案 2 :(得分:4)

好的,我在第一个答案中完全看错了你的问题。这是一个更好的一个:)

超载是你最好的选择。由于比较结果仅取决于Name,因此请创建一个 比较的方法,然后调用它:

private int Compare(string first, string second)
{
    // do comparison
}

public int Compare(Type1 first, Type1 second)
{
    return Compare(first.Name, second.Name):
}

public int Compare(Type2 first, Type2 second)
{
    return Compare(first.Name, second.Name);
}

编辑:

由于你有多个项目,你可以做两件事:

public int Compare(string first1, string second1, X first2, X second2 ...

但这会变得有点难看。另一种方法是提供一个提取值的投影:

private int Compare<T>(T first, T second, Func<T,Tuple<string,int,TypeX,TypeY>> projection)
{
    // test for first==null, second==null, etc...

    var nicerFirst = projection(first);
    var nicerSecond = projection(second);

    // compare objects using nicerFirst.Item1, nicerFirst.Item2, etc.
}

然后您的比较看起来像:

int Compare(Type1 first, Type1 second)
{
    return Compare(first, second, x => Tuple.Create(x.Name, x.Int, x.X, x.Y));
}

答案 3 :(得分:1)

如果它只能 与2种类型一起使用,那么就会产生2次重载。

答案 4 :(得分:1)

重载方法是一种很好的方法,只需要两种特定的类型。为避免重复代码,您可以在场景后面使用泛型:

public int Compare(Type1 first, Type1 second) {
  return Compare<Type1>(first, second);
}

public int Compare(Type2 first, Type2 second) {
  return Compare<Type2>(first, second);
}

private int Compare<T>(T first, T second) {
  ...
}

答案 5 :(得分:0)

也许不是最好的解决方案,但这是我想到的: 你做了一个像这样的方法:

int MainCompare(Type1 first1, Type1 second1, Type2 first2, Type2 second2, bool firsttype){...}

然后你可以用两行比较方法。

int compare(Type1 first, Type1 second){
    return MainCompare(first, second, null, null, true);
}


int compare(Type2 first, Type2 second){
    return MainCompare(null, null, first, second, false);
}

你的MainCompare会根据它使用的类型改变一点。

答案 6 :(得分:0)

这可能是一个无法解决的问题,但您可以为这两个类创建适配器,并让它们实现一个通用接口:

public class MyType1 : ICommonInterface, Type1
{
    // Where you can define 'Somethin' in the common interface
    public string Something 
    { 
        get { return base.Something; } 
        set { base.Something = value; } 
    }

     /* ... */
}

public class MyType2 : ICommonInterface, Type2
{
    // If there is no base.Something on Type2, you can re-name it assuming 
    // its intent is the same as Something
    public string Something
    {
        get { return base.SomethingElse; } 
        set { set base.SomethingElse = value; }
    }        
}

然后你可以基本上完​​全实现@Anthony Pegram(+1)所拥有的:

int Compare<T> (T first, T second) where T : ICommonInterface
{
    return first.Something.CompareTo(second.Something);
}