6

I have a generic method

public static void DoSomething<T>()
{...}

. Now I want to restrict that T.

public static void DoSomething<T>() where T: IInterface1
{...}

But what I really want is allowing multiple interfaces, something like

public static void DoSomething<T>() where T: IInterface1, IInterface2
{...}

But that doesn't work. Compiler says something like

There's no implicit conversion from IInterface1 to IInterface2

There's no implicit conversion from IInterface2 to IInterface1

I thought about letting the classes implement a common interface which I can refer to but I don't have access to the classes.

What possibilities do I have to allow multiple Interfaces?

Thanks, Tobi

Edit: Here's what I wanted to do. I'm developing an Outlook-Add-In. I use this piece of code below quite often.

    public static object GetItemMAPIProperty<T>(AddinExpress.MAPI.ADXMAPIStoreAccessor adxmapiStoreAccessor, object outlookItem, uint property) where T: Outlook.MailItem, Outlook.JournalItem
    {
        AddinExpress.MAPI.MapiItem mapiItem;
        mapiItem = adxmapiStoreAccessor.GetMapiItem(((T)outlookItem));
        return mapiItem != null ? mapiItem.GetProperty(property) : null;
    }

The method GetMapiItem takes an object as long as it's one of Outlook's items (Journal, Mail, Contact,...). That's why I was restricting T. Because it cannot be, say, Outlook.MAPIFolder.

No I've changed the method to

    public static object GetItemMAPIProperty<T>(AddinExpress.MAPI.ADXMAPIStoreAccessor adxmapiStoreAccessor, T outlookItem, uint property)
    {
        AddinExpress.MAPI.MapiItem mapiItem;
        mapiItem = adxmapiStoreAccessor.GetMapiItem(((T)outlookItem));
        return mapiItem.GetProperty(property);
    }

but the developer (In this case I) can give it any Type because the method GetMapiItem accepts an object. I hope that makes sense. I'm not sure if it does for that example but I guess restricting a generic method to multiple Types (with OR) can be a good idea.

4

6 回答 6

3

让 Interface1 和 Interface2 都派生自相同的基本接口。前任:

    public static void DoSomething<T>() where T : ICommon
    {
        //...
    }

    public interface IInterface1 : ICommon
    {}

    public interface IInterface2 : ICommon
    { }

    public interface ICommon
    { }

这样做的好处是您不必在每次添加继承自 ICommon 的新接口时都更新 DoSomething() 定义。

编辑:如果您无法控制界面,您有几个选择。这是你可以做的一件事......

    protected static class DoSomethingServer<T1> where T1 : class
    {

        //Define your allowed types here
        private static List<Type> AllowedTypes = new List<Type> {
            typeof(IInterface1),
            typeof(IInterface2)
        };

        public static MethodInvoker DoSomething()
        {
            //Perform type check
            if (AllowedTypes.Contains(typeof(T1)))
            {
                return DoSomethingImplementation;
            }
            else
            {
                throw new ApplicationException("Wrong Type");
            }
        }

        private static void DoSomethingImplementation()
        {
            //Actual DoSomething work here
            //This is guaranteed to only be called if <T> is in the allowed type list
        }
    }

像这样使用:

DoSomethingServer<IInterface1>.DoSomething();

不幸的是,这会带走编译时类型的安全性,并且如果您尝试输入错误的类型,它只会在运行时崩溃。显然,这不太理想。

于 2009-07-28T16:31:03.810 回答
3

这对我来说编译得很好:

interface I1 { int NumberOne { get; set; } }
interface I2 { int NumberTwo { get; set; } }

static void DoSomething<T>(T item) where T:I1,I2
{
    Console.WriteLine(item.NumberOne);
    Console.WriteLine(item.NumberTwo);
}

所以语法看起来不错……也许是其他原因导致了问题。

于 2009-07-28T16:34:19.827 回答
2

如果您的意思是参数可以是 I1 的实现或 I2 的实现,并且它们是不相关的类型,那么您不能编写一个方法组(即具有相同方法名称的重载)来处理这两种类型。

你甚至不能说(借用纳德!):

    interface I1 { int NumberOne { get; set; } }
    interface I2 { int NumberTwo { get; set; } }

    static void DoSomething<T>(T item) where T : I1
    {
        Console.WriteLine(item.NumberOne);
    }

    static void DoSomething<T>(T item) where T : I2
    {
        Console.WriteLine(item.NumberTwo);
    }

    static void DoSomething<T>(T item) where T : I1, I2
    {
        Console.WriteLine(item.NumberOne);
        Console.WriteLine(item.NumberTwo);
    }

这将为编译器提供一种方法来处理所有可能性,而不会产生歧义。但是为了帮助进行版本控制,C# 会尽量避免添加/删除一个方法会改变另一个方法的适用性的情况。

您需要编写两个不同名称的方法来处理这两个接口。

于 2009-07-28T16:39:07.070 回答
1

一种方法是创建一个扩展接口1和2的附加接口。然后你把这个接口而不是其他2。

这是在java中做到这一点的一种方法;如果我没记错的话,这在 C# 中也应该可以工作

希望有帮助。

问候,托比也是:P

于 2009-07-28T16:30:48.850 回答
1
    public interface IInterfaceBase
    {

    }
    public interface IInterface1 : IInterfaceBase
    {
      ...
    }
    public interface IInterface2 : IInterfaceBase
    {
      ...
    } 

    public static void DoSomething<T>() where T: IInterfaceBase
    {
    }

如果你想让 T 成为 IInterface1 或 IInterface2 使用上面的代码

于 2009-07-28T16:36:35.157 回答
0

Building off of what Earwicker said... names aren't the only way to go. You could also vary the method signatures...

public interface I1 { int NumberOne { get; set; } }
public interface I2 { int NumberTwo { get; set; } }

public static class EitherInterface
{
    public static void DoSomething<T>(I1 item) where T : I1
    {
        Console.WriteLine("I1 : {0}", item.NumberOne);
    }

    public static void DoSomething<T>(I2 item) where T : I2
    {
        Console.WriteLine("I2 : {0}", item.NumberTwo);
    }
}

Which when tested like this:

public class Class12 : I1, I2
{
    public int NumberOne { get; set; }
    public int NumberTwo { get; set; }
}

public class TestClass
{
    public void Test1()
    {
        Class12 z = new Class12();
        EitherInterface.DoSomething<Class12>((I1)z);
        EitherInterface.DoSomething<Class12>((I2)z);
    }
}

Yields this output:

I1 : 0
I2 : 0

This meets the goal of exposing a single method name to the caller, but doesn't help you since you aren't using parameters.

于 2009-07-28T17:33:40.207 回答