繁体   English   中英

如何在C#中诊断和删除模糊引用?

[英]How do I diagnose and remove an ambiguous reference in C#?

(请随意为此问题建议更准确的标题。)

在我的Visual Studio 2015解决方案中,我有三个项目(让我们称之为Alpha,Beta和Gamma)或多或少相同,但不同之处在于它们定义了不同的后端。 这两个项目都将一个类热插入同一个命名空间:

Α:

namespace SharedNamespace {
    public class SharedClass {
        // implement SharedClass using Alpha's backend
    }
}

Beta版:

namespace SharedNamespace {
    public class SharedClass {
        // implement SharedClass using Beta's backend
    }
}

伽玛:

namespace SharedNamespace {
    public class SharedClass {
        // implement SharedClass using Gamma's backend
    }
}

有几个项目使用这个热插拔类,每个类都引用Alpha,Beta或Gamma。 其中一个(让我们称之为Omricon )用于引用Alpha,但现在引用Gamma:

// ...
SharedNamespace.SharedClass sharedClass;
sharedClass.DoThing();
// ...

但是,当我尝试构建Omricon时,C#编译器会给出错误CS0433:

The type 'SharedClass' exists in both 'Alpha, Version=0.0.0.0 (etc)' 
and 'Gamma, Version=0.0.0.0 (etc)'

但是,Omricon 在构建时引用Gamma - 当我进入项目引用列表时,仅出现Gamma引用。 据我了解,Omricon竟然一无所知阿尔法可言,更不用说它定义在同一位置的一类。 只有Omricon无法构建 - 其他使用Alpha和Beta的项目工作正常,当我将Omricon切换回使用Alpha时,它也能正常工作!

在我看来,在其他地方正在维护对Alpha的引用。 如何在我的代码中找到对Alpha的迷路引用,并删除它?

请注意,我已尝试强制完全重建( 如此答案所示 ),并且仍然出现相同的错误,因此它与错误的对象缓存无关。

编辑:澄清倒数第二段

首先,你可能已经意识到: 这是一个可怕的情况 如果您可以避免在引用它们的两个不同程序集中的同一命名命名空间中具有相同的命名类,请避免这种情况 它强烈表明您的应用程序存在架构缺陷。 听起来我应该在第四个程序集中定义一个接口,然后让所有程序集同意使用该接口。

然而, 一种方法来应对这种情况在C#。

编译Omicron时,应该为Alpha.dll,Beta.dll和Gamma.dll提供引用别名:

/reference:AlphaDLL=Alpha.DLL /reference:BetaDLL=Beta.DLL ... etc

然后在Omicron内你说:

extern alias AlphaDLL;
extern alias BetaDLL;
extern alias GammaDLL;

在文件中,然后在该文件中,您可以说:

AlphaDLL::SharedNamespace.SharedClass

为了消除哪一个意图的歧义。

但同样, 不要陷入这种情况 而是创建一个SharedClass实现的接口,并使Alpha,Beta和Gamma实现都使用名称不冲突的类实现该接口。

因此,在与队友进行了一些挖掘之后,我发现即使在项目文件本身中找不到对Alpha的引用,我们的一个.targets文件也指示MSBuild在我背后添加项目引用到Alpha:

<Choose>
    <When Condition=" <!-- needs beta --> ">
        <ItemGroup>
            <ProjectReference Include="$(absdtSln)path\to\Beta">
                ...
            </ProjectReference>
        </ItemGroup>
    </When>
    <Otherwise>
        <ItemGroup>
            <ProjectReference Include="$(absdtSln)path\to\Alpha">
                ...
            </ProjectReference>
        </ItemGroup>
    </Otherwise>
</Choose>

(我认为,这是因为参考Alpha和Beta的项目不必手动执行,正如我试图做的那样,并且是在我正在测试的项目上明确完成的)。

我为Gamma添加了另一个案例,现在情况正常。

(是的, @ Eric ,像这样的东西是另一个证明这是一个可怕的情况。)

具有相同名称的类可以存在于不同的项目中,但它们不能属于同一名称空间。

既然你说Alpha和Beta已经成功构建并且在添加Gamma时问题就开始了,我怀疑Alpha和Beta是通过在构建另一个时禁用一个而单独构建的,反之亦然。 请与团队中的某位熟悉过去如何构建的人员联系。

我认为这个设置背后的原因是你创建了两个具有相同类名的dll(Alpha和Beta),因此可以以相同的方式调用和使用它们。 这会创建两个具有相同签名的dll来执行不同的操作。

你的消息在某种程度上证实了我的怀疑,因为你得到了Alpha和Gamma的问题,但不是Beta。 我认为当你添加Gamma时,Beta被禁用以准备构建Alpha。

正如评论中的其他人所说的那样,你所做的事情是不可能的......你不能在完全相同的命名空间中拥有两个具有完全相同名称的类(除非它们是部分的)。

你有几个选择:

  1. 使用不同的命名空间

好处是您没有这些冲突,并且可以通过其完全限定的命名空间指定您的类实例。

Α:

namespace AlphaNamespace {
    public class SharedClass {
        // implement SharedClass using Alpha's backend
    }
}

Beta版:

namespace BetaNamespace {
    public class SharedClass {
        // implement SharedClass using Beta's backend
    }
}

伽玛:

namespace GammaNamespace {
    public class SharedClass {
        // implement SharedClass using Gamma's backend
    }
}

在这里,omicron将使用伽玛作为

var gamma = new GammaNamespace.SharedClass(...)

  1. 使用部分

部分类文档

当编译器将两个类合并在一起时,您必须合并项目并更改方法名称以避免冲突。 怀疑这会按你想要的方式工作......

Α:

namespace SharedNamespace {
    public partial class SharedClass {
        // implement SharedClass using Alpha's backend
    }
}

Beta版:

namespace SharedNamespace {
    public partial class SharedClass {
        // implement SharedClass using Beta's backend
    }
}

伽玛:

namespace SharedNamespace {
    public partial class SharedClass {
        // implement SharedClass using Gamma's backend
    }
}

  1. 使用策略模式(或带有接口的状态模式而不是具体类)

在这里,您将确定要使用的BaseClass的哪个扩展(Alpha,Beta或Gamma),并通过依赖注入或某种逻辑确定来交换它。

namespace SharedNamespace {
    public class BaseClass{
        // place method abstractions here
    }
}


namespace SharedNamespace {
    public class AlphaClass : BaseClasse {
        // implement BaseClass using Alpha's backend
    }
}

namespace SharedNamespace {
    public class BetaClass : BaseClasse {
        // implement BaseClass using Beta's backend
    }
}

namespace SharedNamespace {
    public class GammaClass : BaseClasse {
        // implement BaseClass using Gamma's backend
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM