c#与方法的接口<;T>;但是实现为concreate

c#与方法的接口<;T>;但是实现为concreate,c#,C#,我创建了这样一个界面: public interface ICacheable { void CloneTo<T>(T entity) where T : class, new(); } 这样我只能传递正确类型的实体 我试着从T开始创建接口,即 public interface ICacheable<T> 公共接口可设置 这就允许我将实现类的方法裁剪为只接受该类型。然而,我再也不能拥有列表了 有人知道我在这里要做的事情是否有可能实现吗?谢谢 如果你不想拥有列

我创建了这样一个界面:

public interface ICacheable {
    void CloneTo<T>(T entity) where T : class, new();
}
这样我只能传递正确类型的实体

我试着从T开始创建接口,即

public interface ICacheable<T>
公共接口可设置
这就允许我将实现类的方法裁剪为只接受该类型。然而,我再也不能拥有
列表了


有人知道我在这里要做的事情是否有可能实现吗?谢谢

如果你不想拥有
列表
,你可以一直拥有
列表

我唯一能想到的其他组织是:

public interface ICacheable
{
    void CloneTo(ICacheable entity);
}

public interface ICacheable<T> : ICacheable where T : ICacheable
{
    void CloneTo(T entity);
}

public abstract class Cacheable<T> : ICacheable<T> where T : ICacheable
{
    void ICacheable.CloneTo(ICacheable entity)
    {
        // here it can fail at runtime though
        CloneTo((T)entity);
    }

    public abstract void CloneTo(T entity);
}

public class MyEntity : Cacheable<MyEntity>
{
    public override void CloneTo(MyEntity entity)
    {
        //...
    }
}
公共接口可设置
{
无效CloneTo(ICacheable实体);
}
公共接口ICacheable:ICacheable其中T:ICacheable
{
无效克隆(T实体);
}
公共抽象类Cacheable:ICacheable其中T:ICacheable
{
void ICacheable.CloneTo(ICacheable实体)
{
//但在这里,它可能会在运行时失败
CloneTo((T)实体);
}
公开摘要无效克隆(T实体);
}
公共类MyEntity:可缓存
{
公共覆盖无效克隆(MyEntity实体)
{
//...
}
}
因此,您可以:

var list = new List<ICacheable>();
list.Add(new MyEntity());
var something = new MyEntity();
// works 
list[0].CloneTo(something);
var list=newlist();
添加(new MyEntity());
var something=new MyEntity();
//工作
列表[0]。CloneTo(某物);
但是,您可能会遇到以下代码问题:

public class SecondEntity : Cacheable<SecondEntity> { ... }
var list = new List<ICacheable>();
list.Add(new MyEntity());
var something = new SecondEntity();
// oops - runtime error
list[0].CloneTo(something);    
公共类第二实体:可缓存{…}
var list=新列表();
添加(new MyEntity());
var something=new SecondEntity();
//oops-运行时错误
列表[0]。CloneTo(某物);

您可以将界面分为两部分,一部分包含依赖类型的成员,另一部分包含不依赖类型的成员:

public interface ICacheable<T> : ICacheable
    where T : class, new()
{
    // All type-dependant members go here
    void CloneTo(T entity);
}

public interface ICacheable
{
    // All type-agnostic members go here
}
公共接口可设置:可设置
其中T:class,new()
{
//所有依赖类型的成员都到这里来
无效克隆(T实体);
}
公共接口iCachable
{
//所有类型不可知论者都到这里来
}
当然,您不能将
CloneTo
与非泛型
ICacheable
类型一起使用

我真正想要的是实现它更像这样:

public class MyEntity : ICacheable {
    public void CloneTo(MyEntity entity) {}
}
有人知道我在这里要做的事情是否有可能实现吗

您希望表达的限制无法在C类型系统中表达。你需要一个“更高”类型的系统;例如,这个限制可以用Haskell表示。(虽然我不想说怎么做;我不是哈斯克尔方面的专家!)

这并不能阻止人们尝试;我在这里描述了实现此限制的最常见的“中断”方式:

我不建议你尝试这种奇怪的模式。不要把C#type系统绑在一起试图表达一个特定的限制,而是问问自己,定义一个接口所固有的多态性到底给你和你的用户带来了什么。回到关键用户场景,看看是否有其他方法来描述您的场景


例如,这里您试图表示“一个可缓存的实体可能被克隆到另一个实体”。伟大的情况就是这样。不要求您使用具有CloneTo方法的iCachable接口来实现它。例如,您可以说实体有一个“clonefrom”方法。看看这是否更容易在类型系统中表达。或者你可以说这里有一个更大的抽象:一些实体可能包含其他实体的克隆,并且任何特定的实体对是否具有这种关系可以由策略引擎确定;现在您必须设计并实现该引擎。等等不是每个业务问题都需要通过在类型系统中嵌入规则来解决。

如果你不知道源类型是什么,你会如何使用
列表?
ICacheable其中t:ICacheable{void CloneTo(t entity);}
&
ICacheable:ICacheable{/code>@Lee我不得不承认这可能不是最佳实践方式,但我有一本字典,它可以将类型和集合一起存储(如果是可编辑的实体)。@Brad Christie,我明白了。。。所以我有两个接口,我自己也在想这条路线,但我的头脑无法理解。谢谢,我会试试这个。如果您需要动态创建一个实现
ICacheable
的包装器,该包装器检查传入参数并调用内部泛型处理程序。您能想出任何方法将ICacheable强制转换为ICacheable,以便我可以对其使用CloneTo方法吗?我将类型作为变量。@Simon我可能误解了你的问题,但是关于只
(ICacheable)cacheable
?当然,这里的
ICacheable
必须是一个
ICacheable
,否则在运行时会得到一个
InvalidCastException
。您可以通过
if(cacheable是可缓存的)
检查类型正确性,谢谢。我遇到的问题是,我将可编辑对象的集合放入字典中,关键是它们的类型。当我检索它们并想调用CloneTo时,尽管我将类型作为变量,但我不能强制转换到它,或者至少不能在编译时转换到它——我需要一种方法作为运行时来执行。有什么想法吗?@Simon泛型的关键是要有强大的类型。因为您是通过
类型
来存储
iCachable
的,所以您不会有强类型。而且,您不能仅通过运行时
类型
来强制转换变量。您可能应该重新考虑您的设计,只需使用
object
而不是通用的
T
。这会帮你省去所有的麻烦,因为我可以告诉你,不管怎样,你可能正在使用一些反射巫术。谢谢,我认为你是对的,我把它复杂化了一点,也许它不需要。我回到了非泛型的ICacheable接口,在我的CloneTo方法中,只需检查所提供的对象是否为实现类类型。非常感谢你的帮助。谢谢你在这方面的投入。你确实是对的,解决办法是退一步,看看是否有
public interface ICacheable<T> : ICacheable
    where T : class, new()
{
    // All type-dependant members go here
    void CloneTo(T entity);
}

public interface ICacheable
{
    // All type-agnostic members go here
}
public class MyEntity : ICacheable {
  public void CloneTo(MyEntity entity) {}
}