【问题标题】:How to return Type T in interface in C#?如何在 C# 的接口中返回 Type T?
【发布时间】:2012-04-09 18:54:34
【问题描述】:

我有一个这样的界面:

public interface IUser{
    //some properties here

    T ToDerived(User u);
}

我是界面开发的新手,所以这就是我想要完成的任务。我会有一个基类

public class User 

没有实现上述接口。然后我会有一个派生类

SalesUser : User, IUser
{
    //no properties needed because they exist in the User class

    SalesUser ToDerived(User u)
    {
        //code for converting a base User to a derived SalesUser
    }
}

我想在SalesUser类中编写ToDerived(User u)的函数,但是在接口中,我不知道如何定义这个,因为我现在在接口中的ToDerived方法声明没有编译。

我希望这是有道理的。

【问题讨论】:

  • Here 是与此问题相关的 Eric 博客的链接。它包括一个看起来很像下面答案的示例,以及使用这种设计机制的陷阱。

标签: c# generics c#-4.0 interface


【解决方案1】:
public interface IUser<T> where T : User
{
    //some properties here

    T ToDerived(User u);
}

SalesUser : User, IUser<SalesUser>
{
    //no properties needed because they exist in the User class

    SalesUser ToDerived(User u)
    {
        //code for converting a base User to a derived SalesUser
    }
}

不确定这是不是你想要的,但我在接口上添加了泛型类型约束,以确保泛型类型是User 或继承自它。

【讨论】:

  • 击败我,但我会添加where T : User
  • @JimSchubert - 我考虑过并在您评论时添加了 ;)
  • @JimSchubert - 不试图竞争,诚实
  • 我不确定我是否喜欢这种设计。 ToDerived 方法应该是静态的,因为您(AFAWK)不需要现有的 SalesUser 来将 User 转换为 SalesUser,因此调用 SalesUser.ToDerived(myUser) 比调用相同的东西更有意义作为实例方法。但是,静态成员不满足接口定义。这告诉我首先不需要定义此方法的接口。您应该改为让 SalesUser 构造函数接受用户,或者简单地将方法设置为静态,以便可以在没有预先存在的实例的情况下使用它。
  • 反对者是我——当时,帖子只是代码,没有解释如何解决问题。解释上还是有点浅。
【解决方案2】:

Oded的回答解决了编译问题,让你定义满足接口的ToDerived方法。但是,正如我在评论中所说,我不确定这是最好的实现。

我遇到的主要问题是在静态上下文中通常需要这样的转换方法。您没有 SalesUser 的实例;你想要一个,并且有一个用户,所以你在静态上下文 (SalesUser.ToDerived(myUser)) 中调用该方法并获得一个 SalesUser(该方法更适合命名为 FromUser() 或类似名称)。您在界面中指定的方法要求您已经拥有一个 SalesUser 才能将 User 转换为 SalesUser。我能想到的唯一需要预先存在的 SalesUser 的情况是“部分克隆”;您正在使用来自传入的用户和调用该方法的 SalesUser 的信息创建一个新的 SalesUser 实例。在所有其他情况下,您要么不需要 SalesUser(转换,如前所述,它应该是静态的),要么您不需要 User(产生新实例的“克隆”或“深拷贝”方法)与您调用该方法的实例相同的数据)。

此外,您的类的消费者必须知道他们必须调用 ToDerived() 才能执行从 User 到 SalesUser 的转换。通常,C# 程序员会期望显式或隐式转换可用:

public class SalesUser
{

    public static explicit operator (User user)
    {
        //perform conversion of User to SalesUser
    }

}

//the above operator permits the following:
mySalesUser = (SalesUser)myUser;

... 或者,如果转换运算符失败,则希望能够使用 User 构造 SalesUser:

public class SalesUser:IUser
{
   public SalesUser(User user)
   {
      //initialize this instance using the User object
   }
}

//the above allows you to do this:
mySalesUser = new SalesUser(myUser);

//and it also allows the definition of a method like this,
//which requires the generic to be an IUser and also requires a constructor with a User
public void DoSomethingWithIUser<T>(User myUser) where T:IUser, new(User)
{ 
    //...which would allow you to perform the "conversion" by creating a T:
    var myT = new T(myUser);
}

现在,静态成员不满足接口定义,接口不能定义静态成员或构造函数签名。这告诉我,IUser 接口不应该尝试定义转换方法;相反,需要某种 IUser 的方法可以简单地指定它,并且用户可以根据需要提供一个实现,而该实现不需要知道它可以转换为自身。

【讨论】:

  • 你说得对,Oded 确实解决了这个问题,并以我正在寻找的确切方式回答了我的问题。但是,我喜欢您对此的解释以及为什么我不应该使用这种设计模式,因为这种特定方法通常是静态方法(我同意)。但是,当我尝试构建您的示例时,请记住,我需要 SalesUser 类来继承基本 User 类。 public class SalesUser : User, IUser 所以,当我尝试这样做时,你的显式方法不起作用。 “不允许用户定义的与基类之间的转换。”
  • 是的,基于构造函数的版本是目前选择的路线。将尝试找出另一种方法,以允许从基本用户到派生销售用户的显式转换。感谢您的帮助。
【解决方案3】:

记住一个接口定义了一个类及其成员而不提供任何实现,你可以创建一个接口,但接口必须有实现类。

【讨论】:

  • 这是如何回答问题的?
  • 我想在SalesUser类中写ToDerived(User u)的函数,但是在接口中,不知道怎么定义为ToDerived方法声明,不知道如果我错了。
猜你喜欢
  • 2015-06-18
  • 2016-11-17
  • 1970-01-01
  • 2019-06-25
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多