如何使一个方法采用两种不同的类型

发布于 2024-09-19 01:52:00 字数 443 浏览 6 评论 0原文

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

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

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

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

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

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

I know this is probably a really simple question but I'm having a brain fart at the moment. I am trying to create a method that can take one of 2 custom types. Basically the body of this method will be identical for both the types as they both have a Name property (I'm doing a comparison on the Name property to use in sorting). How should I do this?

My first thought was just to overload the method with the two types as arguments:

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

but the body of the methods ended up being identical thus it seems like a waste.

My next thought was to use generics but that doesn't seem right because I'm not really making it generic as it can only be used with 2 specific types.

Clarification: The "custom" types are actually not my custom types. What I meant was taht they are not built-in types. I do not have control over what is in these types or the inheritence hierarchy. They just both happen to have the Name property.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

余生共白头 2024-09-26 01:52:00

奇怪的是,到目前为止,没有人发布在我看来是显而易见的选择:将名称作为比较的参数。让调用者从对象中获取 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);

等等。

Oddly enough so far no one has posted what seems to me to be the obvious choice: take the name as the argument of the comparison. Make the caller get the name property out of the object. If all the method needs to use is the name then why are you passing in the rest of the object?

If you need to abstract over the notion of "I can get a name out of this thing" then do that:

Example:

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

And now you can say:

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

and so on.

美胚控场 2024-09-26 01:52:00

如果两种类型派生自相同的基类或使用相同的接口,并且没有其他类使用该基类和/或接口,那么泛型仍然是一个选项。

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

除此之外,拥有两个重载就是正确的选择。

注意:如果您有 .NET 4,则可以将其设为运行时事物并使方法动态化。

int Compare(dynamic first, dynamic second)

在这种情况下,您向其抛出的任何内容都会编译,但如果 Name 属性不存在,它将在运行时崩溃。

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

Generic is still an option if the two types derive from the same base or use the same interface, and no other classes use the base and/or interface.

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

Short of that, having the two overloads is the way to go.

Note: If you have .NET 4, you could make it a runtime thing and make the method dynamic.

int Compare(dynamic first, dynamic second)

In which case anything you throw at it will compile, but it will blow up at runtime if the Name property is not present.

Personally, if I can't modify the type to use a common interface, then I would go with the overloads and get compile-time safety.

吃颗糖壮壮胆 2024-09-26 01:52:00

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

重载是你最好的选择。由于比较结果仅取决于 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);
}

编辑:

由于您有多个项目,因此您可以做两件事do:

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));
}

Okay, I read your question completely wrong in the first answer. Here's a better one :)

Overloads are your best bet. Since the comparison result only depends upon Name, make a method that does that comparison, then call it:

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);
}

Edit:

Since you have more than one item, there's two things you can do:

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

But that's going to get a bit ugly. An alternative is to provide a projection to extract the values:

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.
}

Then your compare looks something like:

int Compare(Type1 first, Type1 second)
{
    return Compare(first, second, x => Tuple.Create(x.Name, x.Int, x.X, x.Y));
}
万劫不复 2024-09-26 01:52:00

如果它只能与两种类型一起使用,则进行 2 个重载。

If it can only be used with 2 types, then make 2 overloads.

倾其所爱 2024-09-26 01:52:00

重载该方法是使其仅采用两种特定类型的好方法。为了避免重复代码,您可以在幕后使用泛型:

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) {
  ...
}

Overloading the method would be a good way to make it take only two specific types. To avoid repeating the code, you can use generics behind the scene:

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) {
  ...
}
饮湿 2024-09-26 01:52:00

也许不是最好的解决方案,但这就是我的想法:
您可以创建一个如下方法:

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

然后您可以用一行来拥有两个 Compare 方法。

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 只会根据它使用的类型而改变一点。

Maybe not the best solution but this is what comes to my mind:
You make a method like:

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

Then you can can have the two Compare methods with one line.

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);
}

your MainCompare will just change a bit depending on what type it's using.

冷弦 2024-09-26 01:52:00

这可能是一个过度的解决方案,但是您可以为这两个类制作适配器,并让它们实现一个通用接口:

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);
}

This is probably an overboard solution, but you could make adapters for the two classes, and have them implement a common interface:

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; }
    }        
}

Then you can implement basically exactly what @Anthony Pegram (+1) had:

int Compare<T> (T first, T second) where T : ICommonInterface
{
    return first.Something.CompareTo(second.Something);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文