我希望能够将已知类型传递给一般函数,但我收到编译错误,因为我无法在设计时转换类型。
考虑我的OnCreate功能:
示例1:
private void OnCreate<T>(T object)
{
object.CurrentDate = DateTime.Now;
object.SpecialProperty = "Hello";
}
示例2:
private void OnCreate<T>(T object)
{
object.BirthDate = DateTime.Now;
object.BirthdayMessage = "Happy Birthday";
}
我想调用OnCreate并传递给它一个对象。该对象恰好是MVC应用程序中的模型对象。我无法预测将什么模型对象传递给OnCreate但我想要访问传递的模型的唯一属性。如上面的示例所示,一个模型具有CurrentDate和SpecialProperty属性;另一个有BirthDate和BirthdayMessage属性。我不想为每个人创建一个特殊功能,因为我有许多不同的模型。此外,此OnCreate函数将从基类继承。这里的想法是提供一个&#34; hook&#34;进入控制器的Create方法,以便有人可以在将模型属性保存到数据库之前更改它们。换句话说,控制器的Create方法会将模型传递给我的OnCreate函数,然后在模型传回之前对模型进行一些工作。
正如您所料,每种型号都有不同的属性。由于这个要求,我意识到我无法通过OnCreate函数进行早期绑定并获得智能感知 - 但我的问题是编译器不会让我引用对象的属性,直到它知道对象类型。我无法在设计时投出它,因为直到运行时我才知道类型。
修改
我认为我的问题不是那么清楚,从答案来判断(对此我感激不尽 - 他们并不是我想要的)。或许最好展示我想如何调用OnCreate():
OnCreate(model);
现在,当OnCreate收到对象&#34; model&#34;时,它需要能够在该模型上设置属性。我想我可以在模型上使用反射并做类似的事情(这只是伪代码 - 仍在学习反射):
if typeof(model) is CustomerModel then
(CustomerModel(model)).BirthDate = "1/1/1960";
(CustomerModel(model)).BirthdayMessage = "Happy Birthday";
elseif typeof(model) is AnotherModel then
(AnotherModel(model)).CurrentDate = DateTime.Now;
(AnotherModel(model)).SpecialProperty = "Hello";
etc...
但我试图避免使用一堆if / then语句。我更喜欢这个电话可能是&#34;路由&#34;到一个特定于传递类型的函数。这样,对OnCreate的调用会将对象发送到重载(?),因此不需要反射逻辑......
第二次编辑
经过进一步思考(没有双关语),我不认为OnCreate函数中有一堆if / else语句是最好的方法。我提出了另一个可能最有效的想法,并且满足了我表达的愿望,即避免出现一堆if / then语句&#34; (在我的第一个编辑中指定):我的想法是让我的模型实现IOnCreate,它将提供.OnCreate()方法。因此,我的&#34;泛型&#34;实现IOnCreate的模型对象可以这样使用:
model.OnCreate();
然后OnCreate函数将知道模型上的属性:
public void OnCreate()
{
this.BirthdayMessage = "Happy Birthday";
etc...
}
我在这里看到两个问题:
1 - 在控制器中我需要测试模型是否实现了IOnCreate - 如果它没有,我就不会尝试调用OnCreate()。 2 - 我需要确保添加一个公共函数(如OnCreate())不会干扰EF6在代码优先项目中生成数据库表的方式。
我现在的问题是这种方法是否最佳......或者是否还有其他想法需要考虑......
答案 0 :(得分:4)
由于T
任何类型,编译器不能指望它有CurrentDate
或SpecialProperty
;
你可以尝试解决这个问题:
public interface IMyInterface {
DateTime CurrentDate {get; set}
String SpecialProperty {get; set}
}
public class MyClassA: IMyInterface {...}
public class MyClassB: IMyInterface {...}
public class MyClassC: IMyInterface {...}
...
private void OnCreate<T>(T value)
where T: IMyInterface // <- T should implement IMyInterface
{
value.CurrentDate = DateTime.Now;
value.SpecialProperty = "Hello";
}
答案 1 :(得分:0)
根据您的示例,Generics
似乎不太可能解决您的问题(您的应用),似乎使用了抽象层(Interface
或Abstract Class
)更合适。
当使用“裸骨”泛型时,任何类型都可以传递给您的方法,因为.Net中的任何类型都是Object
类型,您可以在这些泛型参数上执行任何与对象相关的功能。为了扩展泛型的这种能力来实现我们有Generics Constraints的继承层次结构中最基本的类型,那些允许你限制可以作为泛型参数传递的类型的范围。在您的情况下,您希望使用Type Constraints
,它将类型范围限制为仅实现指定类型的类型。
例如,我们有A
类型,A
类型B
和C
作为派生类,我们希望方法M
仅接受输入如何实现A
:
class Program
{
static void Main(string[] args)
{
M(new A()); // will work
M(new B()); // will work
M(new C()); // will work
M(new D()); // wont work
}
public static string M<T>(T arg)
where T : A
{
return arg.Data;
}
}
public class A { public string Data { get; set; } }
public class B : A { }
public class C : B { }
public class D { }
根据您的上一次编辑,您似乎有两种方法可以解决此问题。
实现抽象层(Interface
):您可能希望添加一个接口并由模型实现。
public static void OnCreate(IBirthable arg)
{
arg.BirthDate = ...;
}
接口:
public interface IBirthable
{
DateTime BirthDate { get; set; }
string BirthdayMessage { get; set; }
}
型号:
public class CustomerModel : IBirthable
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}
public class AnotherModel : IBirthable
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}
使用reflection:如果您选择不使用界面,可能与您的模型没有逻辑连接,您可能需要使用反射。
public static void OnCreate<T>(T arg)
{
var type = arg.GetType();
var birthDateProperty = type.GetProperty("BirthDate");
if (birthDateProperty == null)
throw new ArgumentException("Argument not is implementing the model");
birthDateProperty.SetValue(arg, DateTime.Now);
//And so on...
}
型号:
public class CustomerModel
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}
public class AnotherModel
{
public DateTime BirthDate { get; set; }
public string BirthdayMessage { get; set; }
}