使用反射来查找抽象类型 属性 是一种代码味道吗?
Is using reflection to find type of abstract property a code smell?
假设我有三个 classes:A、B 和 C。A 是抽象的,B 和 C 继承自 A。
我创建了一个 classes 列表。在一个函数中,我需要知道我拥有的 class 的类型:A、B 或 C。我是否使用反射来获取名称?为它分配一个类型变量并检查它?还是我使用抽象从根本上是错误的?
public abstract class A
{
public string Type
{
get;
set;
}
}
public class B : A
{
public B()
{
this.Type = "B";
Console.WriteLine("I am of type B!");
}
}
public class C : A
{
public C()
{
this.Type = "C";
Console.WriteLine("I am of type C!");
}
}
List<A> listOfStuff = new List<A>();
void doSomething()
{
listOfStuff.Add(new A());
listOfStuff.Add(new B());
listOfStuff.Add(new C());
foreach (A item in listOfStuff)
{
doOperation(item);
}
}
void doOperation(A thing1)
{
//Is this bad practice?
if (thing1.GetType().Name == "B")
{
//Do code
}
//Or what about this?
if (thing1.Type == "B")
{
//Do code
}
}
不用那么辛苦。只需使用 is
public abstract class A
{
}
public class B : A
{
public B()
{
Console.WriteLine("I am of type B!");
}
}
public class C : A
{
public C()
{
Console.WriteLine("I am of type C!");
}
}
static List<A> listOfStuff = new List<A>();
public static void doSomething()
{
listOfStuff.Add(new B());
listOfStuff.Add(new C());
foreach (A item in listOfStuff)
{
doOperation(item);
}
}
static void doOperation(A thing1)
{
if (thing1 is B)
{
//Do code for B
}
if (thing1 is C)
{
//Do code for C
}
}
Rob Deary 已经向您展示了如何避免这样做,但他没有具体回答您的问题。
我会说 "code smell" 对于您在 OP 中所写的内容来说太温和了。我能看到的使用反射来查找对象类型的唯一好的案例是某种日志记录或报告功能。 (将要打印 "I got a B" 的内容。)如果需要解决您无法修复的代码中的错误,这可能是可以容忍的。除此之外就别做了。
这可能违反了 Liskov substitution principle, the L in SOLID. 如果列表中有一堆 "A",应该可以在没有 "knowing" 它们的子类型的情况下对它们进行操作。如果它们都将被转换为 A,但您必须重新检查它们以确定它们的实际类型并以不同的方式处理它们,那么它就违背了能够通过它们的基本类型引用它们的目的。
如果不同的类型都可以公开相同的属性(描述区域、维度等),那么接口可能比抽象更好class。
假设我有三个 classes:A、B 和 C。A 是抽象的,B 和 C 继承自 A。
我创建了一个 classes 列表。在一个函数中,我需要知道我拥有的 class 的类型:A、B 或 C。我是否使用反射来获取名称?为它分配一个类型变量并检查它?还是我使用抽象从根本上是错误的?
public abstract class A
{
public string Type
{
get;
set;
}
}
public class B : A
{
public B()
{
this.Type = "B";
Console.WriteLine("I am of type B!");
}
}
public class C : A
{
public C()
{
this.Type = "C";
Console.WriteLine("I am of type C!");
}
}
List<A> listOfStuff = new List<A>();
void doSomething()
{
listOfStuff.Add(new A());
listOfStuff.Add(new B());
listOfStuff.Add(new C());
foreach (A item in listOfStuff)
{
doOperation(item);
}
}
void doOperation(A thing1)
{
//Is this bad practice?
if (thing1.GetType().Name == "B")
{
//Do code
}
//Or what about this?
if (thing1.Type == "B")
{
//Do code
}
}
不用那么辛苦。只需使用 is
public abstract class A
{
}
public class B : A
{
public B()
{
Console.WriteLine("I am of type B!");
}
}
public class C : A
{
public C()
{
Console.WriteLine("I am of type C!");
}
}
static List<A> listOfStuff = new List<A>();
public static void doSomething()
{
listOfStuff.Add(new B());
listOfStuff.Add(new C());
foreach (A item in listOfStuff)
{
doOperation(item);
}
}
static void doOperation(A thing1)
{
if (thing1 is B)
{
//Do code for B
}
if (thing1 is C)
{
//Do code for C
}
}
Rob Deary 已经向您展示了如何避免这样做,但他没有具体回答您的问题。
我会说 "code smell" 对于您在 OP 中所写的内容来说太温和了。我能看到的使用反射来查找对象类型的唯一好的案例是某种日志记录或报告功能。 (将要打印 "I got a B" 的内容。)如果需要解决您无法修复的代码中的错误,这可能是可以容忍的。除此之外就别做了。
这可能违反了 Liskov substitution principle, the L in SOLID. 如果列表中有一堆 "A",应该可以在没有 "knowing" 它们的子类型的情况下对它们进行操作。如果它们都将被转换为 A,但您必须重新检查它们以确定它们的实际类型并以不同的方式处理它们,那么它就违背了能够通过它们的基本类型引用它们的目的。
如果不同的类型都可以公开相同的属性(描述区域、维度等),那么接口可能比抽象更好class。