C# 如何在c中有条件地转换为多个类型#

C# 如何在c中有条件地转换为多个类型#,c#,type-conversion,C#,Type Conversion,我在看一个具有这种模式的函数: if( obj is SpecificClass1 ) { ((SpecificClass1)obj).SomeMethod1(); } else if( obj is SpecificClass2 ) { ((SpecificClass2)obj).SomeMethod2(); } else if( obj is SpecificClass3 ) { ((SpecificClass3)obj).SomeMethod3(); } 并得到一个代码

我在看一个具有这种模式的函数:

if( obj is SpecificClass1 )
{
   ((SpecificClass1)obj).SomeMethod1();
}
else if( obj is SpecificClass2 )
{
   ((SpecificClass2)obj).SomeMethod2();
}
else if( obj is SpecificClass3 )
{
   ((SpecificClass3)obj).SomeMethod3();
}
并得到一个代码分析警告:CA1800不要不必要地强制转换

我可以用什么好的代码模式来替换这段代码,它将是性能和简洁的

更新

我没有说,但是obj是用类型object声明的

我最初在这里问了两个问题。我把其中一个分开(反正还没有人回答):

Interface 最好的方法是引入一个所有类型都实现的接口。这只有在签名匹配(或者没有太多差异)的情况下才可能实现

用作 如果不选择创建接口,则可以通过使用以下模式消除CA消息(尽管这也会引入不必要的强制转换,因此会稍微降低性能):

您也可以将其更改为这种结构(从我的角度来看,上述结构在可读性方面更好):

在字典中注册类型 此外,如果您有许多要检查的类型,可以在字典中注册它们,并对照字典的条目进行检查:

var methodRegistrations = new Dictionary<Type, Action<object> act>();
methodRegistrations.Add(typeof(SpecificClass1), x => ((SpecificClass1)x).SomeMethod1());
methodRegistrations.Add(typeof(SpecificClass2), x => ((SpecificClass2)x).SomeMethod2());
methodRegistrations.Add(typeof(SpecificClass3), x => ((SpecificClass3)x).SomeMethod3());

var registrationKey = (from x in methodRegistrations.Keys 
                       where x.IsAssignableFrom(obj.GetType()).FirstOrDefault();
if (registrationKey != null)
{
    var act = methodRegistrations[registrationKey];
    act(obj);
}
var methodRegistrations=newdictionary();
Add(typeof(SpecificClass1),x=>((SpecificClass1)x).SomeMethod1());
Add(typeof(SpecificClass2),x=>((SpecificClass2)x).SomeMethod2());
Add(typeof(SpecificClass3),x=>((SpecificClass3)x).SomeMethod3());
var registrationKey=(从methodRegistrations.Keys中的x开始)
其中x.IsAssignableFrom(obj.GetType()).FirstOrDefault();
if(registrationKey!=null)
{
var act=方法注册[registrationKey];
法案(obj);
}

请注意,注册很容易扩展,您也可以在操作中使用不同的参数调用方法。

为了避免双重强制转换,您可以执行以下操作

var objClass1= obj as SpecificClass1;
if(objClass1!=null)
   objClass1.SomeMethod1();
关于模式,您可以使所有这些类实现一个公共接口,并使您的方法接收该接口

public void SomeMethod(ISpecificInterface specific)
{
  specific.SomeMethod1();
}

你能在这里做这样的事吗

interface IBaseInterface
{
    void SomeMethod();
}

public class Implementer1:IBaseInterface
{

    public void SomeMethod()
    {
        throw new NotImplementedException();
    }
}

public class Implementer2 : IBaseInterface
{

    public void SomeMethod()
    {
        throw new NotImplementedException();
    }
}

public class Implementer3 : IBaseInterface
{

    public void SomeMethod()
    {
        throw new NotImplementedException();
    }
}
然后,在调用方代码中:

IBaseInterface concrete = GetInstance();
            concrete.SomeMethod();

GetInstance
将根据条件创建类对象。

您的类可以继承如下所示的ISomeMethodInterface:

  public interface ISomeMethodInterface
{ 
     void SomeMethod();
}

public class SpecificClass1 : ISomeMethodInterface
{ 
 //some code
    public void SomeMethod()
    {

    }
}

public class SpecificClass2 : ISomeMethodInterface
{ 
 //some code
    public void SomeMethod()
    {

    }
}

public class SpecificClass3 : ISomeMethodInterface
{ 
 //some code
    public void SomeMethod()
    {

    }
}
在您的通话中:

((ISomeMethodsInterface)obj).SomeMethod();

写一个方法怎么样

public static class ObjectExtensions
{
    public static bool TryCast<T>(this object from, out T to) where T : class
    {
        to = from as T;
        return to != null;
    }
}
好吧,有点粗糙,但是:

    public class BaseClass{}

    public class SubClass1 : BaseClass  
    {
        public void SomeMethod1()
        {
        }
    }

    public class SubClass2 : BaseClass  
    {
        public void SomeMethod2()
        {
        }
    }

    public class Class1
    {
        public Class1()
        {
            var test = new SubClass1();

            var lookup = new Dictionary<Type, Action<object>>
                             {
                                 {typeof (SubClass1), o => ((SubClass1) o).SomeMethod1() },
                                 {typeof (SubClass2), o => ((SubClass2) o).SomeMethod2() }
                             };

            //probably best to check the type exists in the dictionary first, 
            //maybe wrap up the execution into a class of it's own so it's abstracted away
            lookup[test.GetType()](test);

        }
    }
公共类基类{}
公共类子类1:基类
{
公共方法1()
{
}
}
公共类子类2:基类
{
公共方法2()
{
}
}
公共班级1
{
公共类别1()
{
var test=新的子类1();
var lookup=新字典
{
{typeof(subclass 1),o=>((subclass 1)o).SomeMethod1()},
{typeof(subclass 2),o=>((subclass 2)o).SomeMethod2()}
};
//可能最好先检查字典中是否存在类型,
//也许将执行过程封装到它自己的类中,这样它就被抽象出来了
查找[test.GetType()](测试);
}
}

最可扩展的解决方案可能是继承具体类,同时使用调用继承类上正确的
SomeMethodx
方法的
SomeMethod实现来实现接口。这样,您将在保留现有方法的同时保留现有接口

public interface ISomething {
    void SomeMethod();
}

public SpecificClass1Wrapper : SpecificClass1, ISomething {
    void SomeMethod() { SomeMethod1(); }
}
如果对象在存储到对象引用中之前以这种方式包装,则转换到
ISomething
和调用
SomeMethod()
将替换整个If/else组合

另一方面,如果对象来自代码,您无法进行扩展和简洁,但仍然清楚您的目标,那么您可以创建一个简单的helper方法

private bool CallIfType<T>(object obj, Action<T> action) where T : class
{
    var concrete = obj as T;

    if (concrete == null)
        return false;

    action(concrete);
    return true;
}
private bool CallIfType(对象对象,动作动作),其中T:class
{
var混凝土=作为T的obj;
if(concrete==null)
返回false;
行动(具体);
返回true;
}
然后可以将调用编写为简单表达式

var tmp = CallIfType<SpecificClass1>(obj, x => x.SomeMethod1()) ||
          CallIfType<SpecificClass2>(obj, x => x.SomeMethod2()) ||
          CallIfType<SpecificClass3>(obj, x => x.SomeMethod3());

if(tmp)
    Console.WriteLine("One of the methods was called");
var tmp=CallIfType(obj,x=>x.SomeMethod1())||
CallIfType(obj,x=>x.SomeMethod2())||
CallIfType(obj,x=>x.SomeMethod3());
如果(tmp)
WriteLine(“调用了其中一个方法”);

不确定我是否错过了一个目标,但这里有一个可行的选择

if( obj is SpecificClass1 sc1 )
{
   sc1.SomeMethod1();
}
else if( obj is SpecificClass2 sc2 )
{
   sc2.SomeMethod2();
}
else if( obj is SpecificClass3 sc3 )
{
   sc3.SomeMethod3();
}
else
{
   throw new exception();
}
你也可以

switch (obj)
{
    case SpecificClass1 sc1:
        sc1.SomeMethod1();
        break;
    case SpecificClass2 sc1:
        sc2.SomeMethod2();
        break;
    case SpecificClass3 sc1:
        sc3.SomeMethod3();
        break;
    default:
        throw new Exception();
}

如果你有很多这样的问题,那么考虑是否可以用超载或泛型来消除它。@ SuluSt--使用访问者模式。不幸的是,我没有修改SpecificClassX所来自的库的能力。你能隐藏隐藏在一个从图书馆扩展的一个适配器类中的丑陋吗?这不会招致麻烦吗?mance惩罚。这段代码总是对每个特定的类类型进行强制转换,即使第一个可能匹配…所以在这种情况下,我认为只需要一个强制转换。我宁愿根据需要进行软强制转换,但我不喜欢嵌套的if/else;我宁愿显式返回,或者在同一级别没有“else”的情况下进行简单的if。@ScottLangham:是的,就是这样我对“不必要的强制转换”的意思是什么。我会澄清一下。你必须小心不要在没有强制转换的范围内使用一个变量。例如,不要在sc2.SomeMethod2()所在的主体中使用sc1。
var tmp = CallIfType<SpecificClass1>(obj, x => x.SomeMethod1()) ||
          CallIfType<SpecificClass2>(obj, x => x.SomeMethod2()) ||
          CallIfType<SpecificClass3>(obj, x => x.SomeMethod3());

if(tmp)
    Console.WriteLine("One of the methods was called");
if( obj is SpecificClass1 sc1 )
{
   sc1.SomeMethod1();
}
else if( obj is SpecificClass2 sc2 )
{
   sc2.SomeMethod2();
}
else if( obj is SpecificClass3 sc3 )
{
   sc3.SomeMethod3();
}
else
{
   throw new exception();
}
switch (obj)
{
    case SpecificClass1 sc1:
        sc1.SomeMethod1();
        break;
    case SpecificClass2 sc1:
        sc2.SomeMethod2();
        break;
    case SpecificClass3 sc1:
        sc3.SomeMethod3();
        break;
    default:
        throw new Exception();
}