gpt4 book ai didi

c# - 扩展方法和类型推断

转载 作者:行者123 更新时间:2023-11-30 12:30:19 28 4
gpt4 key购买 nike

我正在尝试使用大量扩展基本描述符的泛型和描述符创建一个流畅的接口(interface)。我已将它放在 github 存储库中,因为将所有代码粘贴到此处会使它变得不可读。

在阅读 Eric Lippert 关于类型约束的文章 (http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx) 和阅读 No type inference with generic extension method 之后我对这个主题有了更好的理解,但我仍然有问题。

假设你有一些允许流畅调用的类:

var giraffe = new Giraffe();
new ZooKeeper<Giraffe>()
.Name("Jaap")
.FeedAnimal(giraffe);

var reptile = new Reptile();
new ExperiencedZooKeeper<Reptile>()
.Name("Martijn")
.FeedAnimal(reptile)
.CureAnimal(reptile);

类看起来像这样:

public class ZooKeeper<T>
where T : Animal
{
internal string name;
internal List<T> animalsFed = new List<T>();

// this method needs to be fluent
public ZooKeeper<T> Name(string name)
{
this.name = name;
return this;
}

// this method needs to be fluent
public ZooKeeper<T> FeedAnimal(T animal)
{
animalsFed.Add(animal);
return this;
}
}

public class ExperiencedZooKeeper<T> : ZooKeeper<T>
where T : Animal
{
internal List<T> animalsCured = new List<T>();

// this method needs to be fluent
// but we must new it in order to be able to call CureAnimal after this
public new ExperiencedZooKeeper<T> Name(string name)
{
base.Name(name);
return this;
}

// this method needs to be fluent
// but we must new it in order to be able to call CureAnimal after this
public new ExperiencedZooKeeper<T> FeedAnimal(T animal)
{
base.FeedAnimal(animal);
return this;
}

// this method needs to be fluent
public ExperiencedZooKeeper<T> CureAnimal(T animal)
{
animalsCured.Add(animal);
return this;
}
}

我试图摆脱 ExperiencedZooKeeper 中隐藏 ZooKeeper 实现的"new"方法。不同之处在于 ExperiencedZooKeeper 中的 new 方法返回正确的类型。据我所知,如果没有 new 方法,就无法做到这一点。

我尝试采用的另一种方法是将“setter”移至扩展方法。这适用于 .Name() 方法,但它引入了一个包含内部字段的 ZooKeeperBase:

public abstract class ZooKeeperBase
{
internal string name;

}

public class ZooKeeper<T> : ZooKeeperBase
where T : Animal
{
internal List<T> animalsFed = new List<T>();


// this method needs to be fluent
public ZooKeeper<T> FeedAnimal(T animal)
{
animalsFed.Add(animal);
return this;
}
}

public static class ZooKeeperExtensions
{

// this method needs to be fluent
public static TZooKeeper Name<TZooKeeper>(this TZooKeeper zooKeeper, string name)
where TZooKeeper : ZooKeeperBase
{
zooKeeper.name = name;
return zooKeeper;
}
}

但这种方法不适用于 FeedAnimal(T animal),它需要一个额外的类型参数:

// this method needs to be fluent
public static TZooKeeper FeedAnimal<TZooKeeper, T>(this TZooKeeper zooKeeper, T animal)
where TZooKeeper : ZooKeeper<T>
where T : Animal
{
zooKeeper.animalsFed.Add(animal);
return zooKeeper;
}

这仍然可以并且运行良好,您仍然可以流利地调用它:

new ExperiencedZooKeeper<Reptile>()
.Name("Martijn")
.FeedAnimal(reptile)
.CureAnimal(reptile);

当我尝试使以下方法流畅时,真​​正的问题开始了:

public static TZooKeeper Favorite<TZooKeeper, T>(this TZooKeeper zooKeeper, Func<T, bool> animalSelector)
where TZooKeeper : ZooKeeper<T>
where T : Animal
{
zooKeeper.favoriteAnimal = zooKeeper.animalsFed.FirstOrDefault(animalSelector);
return zooKeeper;
}

你不能像这样调用Favorite:

new ExperiencedZooKeeper<Reptile>()
.Name("Eric")
.FeedAnimal(reptile)
.FeedAnimal(new Reptile())
.Favorite(r => r == reptile)

因为它会导致与 No type inference with generic extension method 相同的问题但是,这种情况稍微复杂一些,因为我们已经有了一个 Type 参数 TZookKeeper,它描述了我们需要的 T。但是就像 Eric Lipperts 的博客文章一样,类型约束不是签名的一部分:

The type arguments for method 'TestTypeInference5.ZooKeeperExtensions.Favorite<TZooKeeper,T>(TZooKeeper, System.Func<T,bool>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

完整代码请引用https://github.com/q42jaap/TestTypeInference这个 repo 中的 README 实际上解释了我试图解决的现实生活中的问题。

所以真正的问题是,有没有一种方法可以创建这种流畅的方法风格,而无需将 ZooKeeper 的每个方法都添加到 ZooKeeper 的每个子类中,new 隐藏 ZooKeeper 本身的方法?

最佳答案

一种可能性是为每个级别创建一个基类,并从中派生一个空的处理程序类:

基类:

public abstract class ZooKeeperBase<TZooKeeper, TAnimal>
where TZooKeeper : ZooKeeperBase<TZooKeeper, TAnimal>
where TAnimal : Animal
{
private string name;
private List<TAnimal> animalsFed = new List<TAnimal>();
private TAnimal favoriteAnimal;

public TZooKeeper Name(string name)
{
this.name = name;
return (TZooKeeper)this;
}

public TZooKeeper FeedAnimal(TAnimal animal)
{
animalsFed.Add(animal);
return (TZooKeeper)this;
}

public TZooKeeper Favorite(Func<TAnimal, bool> animalSelector)
{
favoriteAnimal = animalsFed.FirstOrDefault(animalSelector);
return (TZooKeeper)this;
}
}

public abstract class ExperiencedZooKeeperBase<TZooKeeper, TAnimal>
: ZooKeeperBase<TZooKeeper, TAnimal>
where TZooKeeper : ExperiencedZooKeeperBase<TZooKeeper, TAnimal>
where TAnimal : Animal
{
private List<TAnimal> animalsCured = new List<TAnimal>();

public TZooKeeper CureAnimal(TAnimal animal)
{
animalsCured.Add(animal);
return (TZooKeeper)this;
}
}

处理程序类:

public class ZooKeeper<T> : ZooKeeperBase<ZooKeeper<T>, T>
where T : Animal
{
}

public class ExperiencedZooKeeper<T>
: ExperiencedZooKeeperBase<ExperiencedZooKeeper<T>, T>
where T : Animal
{
}

用法与您在问题中显示的一样。

关于c# - 扩展方法和类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16442596/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com