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