简体   繁体   English

c#接口方法<T>但实现为concreate

[英]c# interface with method<T> but implement as concreate

I've created an Interface like so: 我创建了一个这样的接口:

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

However, when I implement the interface in a class, I have to define the CloneTo method also using T as the type as follows: 但是,当我在类中实现接口时,我必须使用T作为类型定义CloneTo方法,如下所示:

public class MyEntity : ICacheable {
    public void CloneTo<T>(T genericEntity) where T : class, new() {}
}

This does compile and run. 这会编译并运行。 However, it's not ideal as I could pass any other item that implements ICacheable to the method where I only want to be able to send an instance of the class. 但是,它并不理想,因为我可以将任何其他实现ICacheable的项目传递给我只希望能够发送该类实例的方法。 What I really want is to implement it more like this: 我真正想要的是更像这样实现它:

public class MyEntity : ICacheable {
    public void CloneTo(MyEntity entity) {}
}

That way I could only pass the proper type of entity. 这样我只能传递适当类型的实体。

I tried instead creating the interface as of T, ie 我尝试从T创建界面,即

public interface ICacheable<T>

Which did then allow me to tailor the implementing class's method to only accept that type. 然后,这允许我定制实现类的方法以仅接受该类型。 However, I then could no longer have a List<ICacheable> . 但是,我再也没有List<ICacheable>

Does anyone know if it's possible to achieve what I'm trying to do here? 有谁知道是否有可能实现我在这里尝试做的事情? Thanks! 谢谢!

If you don't want to have List<ICacheable<MyEntity>> you can always have List<object> . 如果您不想拥有List<ICacheable<MyEntity>> ,则可以始终使用List<object>

Only other organization I can think off is something like: 只有我能想到的其他组织是这样的:

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)
    {
        //...
    }
}

So you can have: 所以你可以:

var list = new List<ICacheable>();
list.Add(new MyEntity());
var something = new MyEntity();
// works 
list[0].CloneTo(something);

However you can run into issues with code like: 但是,您可能遇到以下代码的问题:

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);    

You can split your interface to two parts, one containing type-dependant members, another containing type-agnostic members: 您可以将界面拆分为两部分,一部分包含依赖于类型的成员,另一部分包含与类型无关的成员:

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
}

Of course, you won't be able to use CloneTo with the non-generic ICacheable type. 当然,您将无法将CloneTo与非通用ICacheable类型一起使用。

What I really want is to implement it more like this: 我真正想要的是更像这样实现它:

public class MyEntity : ICacheable {
  public void CloneTo(MyEntity entity) {}
}

Does anyone know if it's possible to achieve what I'm trying to do here? 有谁知道是否有可能实现我在这里尝试做的事情?

The restriction you wish to express cannot be expressed in the C# type system. 您希望表达的限制无法在C#类型系统中表达。 You'd need a "higher" type system; 你需要一个“更高”的类型系统; this restriction could be expressed in Haskell for instance. 例如,这种限制可以在Haskell中表达。 (Though I would not care to say how; I am no expert on Haskell!) (虽然我不想怎么说;我不是Haskell的专家!)

This does not stop people from trying; 这并不能阻止人们尝试; I describe the most common "broken" way I see to implement this restriction here: 我描述了我在这里实现此限制的最常见“破碎”方式:

https://blogs.msdn.microsoft.com/ericlippert/2011/02/03/curiouser-and-curiouser/ https://blogs.msdn.microsoft.com/ericlippert/2011/02/03/curiouser-and-curiouser/

I do not recommend that you attempt this curious pattern. 我不建议您尝试这种好奇的模式。 Rather than tying the C# type system in knots to try to express a particular restriction, ask yourself what the polymorphism inherent in defining an interface really buys you and your users. 而不是将C#类型系统绑在结上以试图表达特定的限制,而不是问问自己定义界面所固有的多态性真正为您和您的用户带来了什么。 Go back to the key user scenarios and see if there is another way to describe your scenario. 回到关键用户场景,看看是否有另一种方式来描述您的场景。

For example, here you're trying to represent "a cachable entity may be cloned to another entity". 例如,在这里,您试图表示“可以将可缓存的实体克隆到另一个实体”。 Great. 大。 That's the scenario. 这就是场景。 There is no requirement that you implement that with an ICacheable interface that has a CloneTo method. 不要求使用具有CloneTo方法的ICacheable接口实现它。 You could for example say that entities have a "clone from" method. 例如,您可以说实体具有“克隆自”方法。 See if that is easier to express in the type system. 看看在类型系统中是否更容易表达。 Or you could say that there is a bigger abstraction here: that some entities may contain clones of others, and whether or not any particular pair of entities have that relationship can be determined by a policy engine; 或者你可以说这里有一个更大的抽象:一些实体可能包含其他实体的克隆,以及任何特定的实体对是否具有该关系可以由策略引擎确定; now you must design and implement that engine. 现在你必须设计并实现该引擎。 And so on. 等等。 Not every business problem needs to be solved by embedding its rules in the type system. 并非每个业务问题都需要通过在规则系统中嵌入其规则来解决。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM