显式界面和通用/动态类型转换

时间:2015-08-27 12:55:14

标签: c# generics dynamic explicit-interface

在我陈述我的问题之前,让我提供一些有关我尝试做的事情的背景信息,因为也许有更好的方法来实现它。

我有一个类C,它继承了两个接口AB

public interface A
{
    void DoStuff();
}

public interface B
{
    void DoStuff();
}

C为DoStuff实现了两个不同的主体。

void A.DoStuff()
{
    Console.WriteLine("A");
}

void B.DoStuff()
{
    Console.WriteLine("B");
}

我当然知道DoStuff可以在下面调用。

var c = new C();
var a = (A)c;
a.DoStuff();
var b = (B)c;
b.DoStuff();

我想要做的是避免将C转换为AB,然后在DoStuff或{{1}上调用A }。

所以我觉得我可以实现一个通用的方法为我做这个,所以我首先尝试这样。

B

当然,考虑到您可以将public void DoStuff<T>() { var i = (T)this; i.DoStuff(); } 转换为this并且它会导致编译器错误,但它不会起作用,因此我的下一步是尝试创建一个传递实例的静态方法T然后在那里做了转换。

this

我没想到会这样,但值得一试。正如我所料,它会导致编译器错误,因为private static To ConvertToDoStuffInterface<From, To>(From from) { return (To)from; } 无法显式转换为From

我的最后一种方法是使用To关键字,当然它通过dynamic来平滑,但是一旦我尝试拨打ConvertToDoStuffInterface,它会抛出一个DoStuff我有点儿怀疑它可能会。我知道为什么会抛出异常,当然因为它无法将结果从RuntimeBinderException正确绑定到任何类型,我需要进行某种类型的转换。

以下是ConvertToDoStuffInterface用法的代码。

dynamic

我的问题是,如果没有更好的方法可以使用泛型或private static dynamic ConvertToDoStuffInterface<T>(dynamic from) { return (T)from; } public void DoStuff<T>() { var i = ConvertToDoStuffInterface<T>(this); i.DoStuff(); } 来实现这一目标,我将如何进行从dynamicdynamic的转换?有没有办法可以检查传递给T的类型是否有方法DoStuff<T>,然后允许我最初尝试的内容?

澄清我希望能做的事情是这样的

DoStuff

这是我的var c = new C(); c.DoStuff<A>(); // Calls A.DoStuff() c.DoStuff<B>(); // Calls B.DoStuff() 实施。

C

3 个答案:

答案 0 :(得分:2)

您可以使用这两个InvokeAs扩展方法

public static void InvokeAs<T>(this object obj, Action<T> action)
{
    action((T) obj);
}

public static TResult InvokeAs<T, TResult>(this object obj, Func<T, TResult> func)
{
    return func((T) obj);
}

然后像这样使用:

var c = new C();

c.InvokeAs<A>(x => x.DoStuff());
c.InvokeAs<B>(x => x.DoStuff());

但正如评论中指出的那样,((B) c).DoStuff()并不是那么糟糕。

答案 1 :(得分:1)

要完全按照您的意愿行事,您可以使用反射:

class C : A, B
{
    void B.DoStuff()
    {
        Console.WriteLine("B");
    }

    void A.DoStuff()
    {
        Console.WriteLine("A");
    }

    public void DoStuff<T>() 
    {
        var mi = typeof(T).GetMethod("DoStuff");
        mi.Invoke(this, new object[] { });
    }
}
然后是电话:

        var c = new C();
        c.DoStuff<A>();
        c.DoStuff<B>();
        Console.ReadLine();

按预期工作。 显然,如果存在“DoStuff”方法,你必须在DoStuff方法中进行适当的验证,等等。

然而 - 我不知道用例 - 但对我而言,似乎并不那么明显,为什么这对你来说比铸造更好。

答案 2 :(得分:1)

我同意强制转换可能是最干净的(假设您无法修复接口中的名称冲突),但另一种方法是在C上创建两个实例方法来包装接口调用:

public class C : A, B
{        
    public void DoStuff<T>()
    {
        // ... DoStuff<T> implementation here ...
    }

    void A.DoStuff()
    {
        Console.WriteLine("A");
    }

    void B.DoStuff()
    {
        Console.WriteLine("B");
    }

    public void DoStuffAsA() { ((A)this).DoStuff(); }
    public void DoStuffAsB() { ((B)this).DoStuff(); }
}

至少它为您提供dynamic,反射和泛型不具备的编译时安全性。