I've found couple of questions on the same topic here, however I couldn't find what I need. Basically I am searching for this kind of magic:
public class BaseClass
{
public int DerivedТype { get; set; }
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
DerivedТype = 1;
Property = initialValue;
}
public T Property { get; set; }
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
DerivedТype = 2;
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public float OtherProperty { get; set; }
}
public class Program
{
public static void Main()
{
List<BaseClass> baseClassList = new List<BaseClass>();
baseClassList.Add(new DerivedClass<int>(5));
baseClassList.Add(new OtherDerivedClass<float>(6));
foreach (var derived in baseClassList)
{
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
}
}
}
I want a list of BaseClass where I can insert instances of DerivedClass and OtherDerivedClass. So far so good.
DerivedClass and OtherDerivedClass hold different properties so I really have no idea how access them. Also I don't want to use any weired casts. So this part of the code prevents me from building.
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
Any ideas would be appreciated. Thank you in advance!
答案 0 :(得分:1)
这看起来像是一个可以用多态解决的问题。我会为您的应用制作一个与您在示例中完全相同的应用版本,但如果有更多关于您的目标目标的信息,则解决方案可能会有所不同。
public abstract class BaseClass
{
public abstract void DoSomething();
public abstract void GetData(Dictionary<string,string> container);
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
public override void DoSomething()
{
Console.WriteLine(Property);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(Property), "{Property}");
}
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public override void DoSomething()
{
Console.WriteLine(OtherProperty);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(OtherProperty), "{OtherProperty}");
container.Add(nameof(OtherProperty2), "{OtherProperty2}");
}
}
你的foreach循环可以简单如下:
foreach(var derived in baseClassList) derived.DoSomething();
这是使用OO执行此类操作的正确方法。不需要DerivedType整数,因为对象知道它是什么类型以及做什么。这就是人们使用多态的原因。它简单而优雅,面向对象。将DoSomething扩展或更改为更适合您尝试做的事情。
OP提出了他自己的解决方案,但如果目标是对更有意义的数据做一些事情,你也可以将一个对象传递给一个允许你这样做的抽象方法。我添加了一个GetData方法,它将所有属性值作为字符串返回。第二种类型的字典也可以是object
,实际值存储在字典中。
BaseClass也可以是一个常规类,其中包含一个方法,用字符串键返回object
值的IDictionary。该方法可以使用反射来获取它所基于的任何类的所有属性值。但是,反射有更多的开销,因此从执行的角度来看,这不是最有效的方法。
检查对象是否属于某种类型的正确方法是使用is
运算符,例如:
if(derived is DerivedType<int>)
{
// Do what you need to do with the specific object type
}
如果你知道你要投射这个物体,正如阿多西所指出的那样,你会使用:
var castedValue = derived as DerivedType<int>;
if(castedValue != null)
{
// Do what you need to do with castedValue
}
如果对象不是DerivedType<int>
类型,则返回null。尝试使用(DerivedType)派生会导致无效的强制转换异常。
答案 1 :(得分:0)
如果您不介意使用运行时类型,可以使用dynamic
。
例如:
List<BaseClass> baseClassList = new List<BaseClass>();
baseClassList.Add(new DerivedClass<int>(5));
baseClassList.Add(new OtherDerivedClass<float>(6));
// Here use "dynamic"
foreach (dynamic derived in baseClassList)
{
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
}
答案 2 :(得分:0)
据我所知,你想要的是不可能而不是一个好主意。 Typechecking在编译时完成。像Dynamic这样的东西可以将这些检查移动到运行时,但它会导致各种问题(带动态参数的函数也会返回动态)。
如果你至少得到了C#7.0,你至少可以为它编写一个开关。旧开关仅支持几个选择值类型和字符串的值与常量。但C#7.0引入了pattern matching。有了它,您甚至可以使用is
检查作为案例的一部分。
答案 3 :(得分:0)
谢谢大家的支持!我决定简单地使用演员。
public class BaseClass
{
public int DataТype { get; set; }
public object Data { get; set; }
}
public class DataClass<T>
{
public DataClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
List<BaseClass> listBaseClass = new List<BaseClass>();
BaseClass dummy = new BaseClass();
dummy.DataТype = 1;
dummy.Data = new DataClass<int>(50);
listBaseClass.Add(dummy);
if (listBaseClass[0].DataТype == 1)
{
DataClass<int> casted = (DataClass<int>)listBaseClass[0].Data;
Console.WriteLine(casted.Property);
}
}
}