bud*_*ead 5 c# generics inheritance
我有以下基类:
public class Base
{
public string LogicalName { get; set; }
public int NumberOfChars { get; set; }
public Base()
{
}
public Base(string logicalName, int numberOfChars)
{
LogicalName = logicalName;
NumberOfChars = numberOfChars;
}
}
Run Code Online (Sandbox Code Playgroud)
以及以下派生类:
public class Derived1 : Base
{
public const string EntityLogicalName = "Name1";
public const int EntityNumberOfChars = 30;
public Derived1() : base(EntityLogicalName, EntityNumberOfChars)
{
}
}
public class Derived2 : Base
{
public const string EntityLogicalName = "Name2";
public const int EntityNumberOfChars = 50;
public Derived2()
: base(EntityLogicalName, EntityNumberOfChars)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我也有这个由服务提供的功能:
public IEnumerable<T> GetEntities<T>(string entityName, int numberOfChars) where T : Base
{
//Some code to get the entities
}
Run Code Online (Sandbox Code Playgroud)
我的问题是如何通常调用此函数?我想用看起来像这样的东西来调用它:
public void TestEntities<T>() where T : Base
{
var entities = GetEntities<T>(T.EntityLogicalName, T.EntityNumberOfChars);
//some other code to test the entities
}
Run Code Online (Sandbox Code Playgroud)
这当然不起作用,因为此时T未知.我怎样才能完成与此相似的事情?EntityLogicalName和EntityNumberOfChars是所有Base派生类具有的特征,并且它们永远不会为每个派生类更改.我可以从Base类中获取它们而不实例化对象或其他我没有看到的方式吗?
用getter抽象属性替换常量
public abstract class Base
{
public abstract string LogicalName { get; }
public abstract int NumberOfChars { get; }
public Base()
{
}
}
public class Derived1 : Base
{
public string LogicalName { get { return "Name1"; } }
public int NumberOfChars { get { return 30; } }
public Derived1() : base()
{
}
}
Run Code Online (Sandbox Code Playgroud)
此外,您将能够将一些逻辑放入重写的getter中,例如:
...
public string LogicalName { get { return this.EntityMap.Name; } }
...
Run Code Online (Sandbox Code Playgroud)
更新:您不希望从类中实例化对象但希望能够以强类型方式获取该字符串的事实可以通过一种更多方式处理.它与上面的答案完全分开(因为你不能在c#中覆盖静态道具).请考虑以下代码.我们在这里再添加一个类,但LocatorInner可以是BaseClass的成员.我们在几个现有的应用程序中使用了这种方法:
public class Locator
{
public static class LocatorInner<T> where T : BaseClass
{
public static string Name { get; set; }
}
public static string GetName<T>() where T : BaseClass
{
return LocatorInner<T>.Name;
}
public static void SetName<T>(string name) where T : BaseClass
{
LocatorInner<T>.Name = name;
}
}
public class BaseClass
{
}
public class DerivedClass: BaseClass
{
static DerivedClass()
{
Locator.LocatorInner<DerivedClass>.Name = "me";
}
}
public class TestClass<T> where T : BaseClass
{
public void Method()
{
var name = Locator.GetName<T>();
}
}
Run Code Online (Sandbox Code Playgroud)
恕我直言,我相信在这里使用常量是一个糟糕的设计决策。
您可以使用 @vittore 方法解决问题,但对我来说,如果您想从通用参数中获取数据,您应该使用带有属性的元T编程
例如,怎么样:
public class LogicalNameAttribute : Attribute
{
public LogicalNameAttribute(string name)
{
Name = name;
}
public string Name { get; private set; }
}
public class NumberOfCharsAttribute : Attribute
{
public NumberOfCharsAttribute (int number)
{
Number = number;
}
public string Number { get; private set; }
}
[LogicalName("Name1"), NumberOfChars(30)]
public class Derived1 : Base
{
public Derived1() : base()
{
}
}
Run Code Online (Sandbox Code Playgroud)
现在您的服务方法可以提取属性元数据,如下所示:
public void TestEntities<T>() where T : Base
{
LogicalNameAttribute logicalNameAttr = typeof(T).GetCustomAttribute<LogicalNameAttribute>();
NumberOfCharsAttribute numberOfCharsAttr = typeof(T).GetCustomAttribute<NumberOfCharsAttribute >();
Contract.Assert(logicalNameAttr != null);
Contract.Assert(numberOfCharsAttr != null);
string logicalName = logicalNameAttr.Name;
int numberOfChars = numberOfCharsAttr.Number;
// Other stuff
}
Run Code Online (Sandbox Code Playgroud)
存在性能损失,因为您需要使用反射来获取应用于 的属性T,但您可以获得不强制派生类提供此静态信息的灵活性。