c# - 将泛型类型声明为接口(interface)的属性?

标签 c# generics

我有一个 Generic 类型,它用于为要持久保存的对象提供一些元数据:

public class PersistedElementDefinition<T> where T: IPersistedObject{
    List<PersistedPropertyDefinition<T>> PropertiesToPersist {get;set;}
}

public class PersistedPropertyDefinition<T> where T: IPersistedObject{
        public Func<T, object> PropertyGetter{get;set;}
        public Action<T, object> PropertySetter {get;set;}
}

我有我的 IPersistedObject可以给出他的定义

public interface IPersistedObject{
    PersistedElementDefinition<TypeOfTheImplementingType> Definition {get;}
}

我的想法是,如果我实现 IPersistedObject我应该这样实现它:

public class MyPersistedObject:IPersistedObject{
    PersistedElementDefinition<MyPersistedObject> Definition{get;}
}

当我坚持我的课时有以下事情:

不能做以下事情:

public interface IPersistedObject<T>{
    PersistedElementDefinition<T> Definition {get;}
}

因为:

  1. 它允许有一个 MyPersistedObject<SomeOtherObject
  2. 有时我会收到一个对象,我应该能够查看它是否实现了 IPersistedObject 并使用它执行一些自定义操作。

对于 2,这是一个示例,说明如果我有一个通用接口(interface),我将面临什么样的问题:

public void Persist<T>(T objectToPersist)where T:IPersistedObject{
    ...
    foreach(PersistedPropertyDefinition<T> property in objectToPersist.PropertiesToPersist){
        object objectToSerialize = property.ObjectGetter(objectToPersist);
        if(objectToSerialize is IPersistedObject<___Don't know how to put something generic here___>){
            Persist((IPersistedObject<___Don't know how to put something generic here___>)objectToSerialize);
        }
    }
    ...
}

是否有可能在 C# 中声明具有实现类型的泛型属性的接口(interface)?

最佳答案

您可以使用奇怪的重复模板模式进一步锁定它。它不是防弹的,但假设您不是受虐狂,并且您不介意理论上可以创建违反您试图保证的不变量的接口(interface)的无意义实现这一事实,您可以这样做:

public interface IPersistedObject<T> where T : IPersistedObject<T>
{
    PersistedElementDefinition<T> Definition {get;}
}

public class PersistedElementDefinition<T> where T: IPersistedObject<T>
{
    ...
}

public class MyPersistedObject : IPersistedObject<MyPersistedObject>
{
    // Here, you are forced to implement a PersistedElementDefinition<MyPersistedObject>,
    // which presumably is the reason behind this whole song and dance

    PersistedDefinition<MyPersistedObject> Definition { get; }
}

问题在于,正如您一开始所注意到的,您可以简单地定义 public class MyPersistedObject : IPersistedObject<MyOtherPersistedObject> , 并最终破坏了你试图拼凑的契约(Contract),简单来说就是:

A persisted object must have a gettable definition that is a persisted element definition of its own type

C# 类型系统根本无法优雅地处理这个问题。我的建议是早点出去,换成objectdynamic在可能的情况下,学会忍受某些编译时间保证的丢失。

假设您愿意牺牲一些编译时安全性,您可以这样做:

class Program
{
    static void Main(string[] args)
    {
        var mpo = new MyPersistedObject();
        var ptp = mpo.Definition.PropertiesToPersist;
    }
}

public class PersistedElementDefinition<T> where T : IPersistedObject
{
    private readonly List<PersistedPropertyDefinition<T>> _propsToPersist = new List<PersistedPropertyDefinition<T>>();
    public List<PersistedPropertyDefinition<T>> PropertiesToPersist
    {
        get { return _propsToPersist; }
    }
}

public class PersistedPropertyDefinition<T> where T : IPersistedObject
{
    public Func<T, object> PropertyGetter { get; set; }
    public Action<T, object> PropertySetter { get; set; }
}

public interface IPersistedObject
{
    dynamic Definition { get; }
}

public class MyPersistedObject : IPersistedObject
{
    private readonly PersistedElementDefinition<MyPersistedObject> _definition = new PersistedElementDefinition<MyPersistedObject>();
    public dynamic Definition { get { return _definition; } }
}

关于c# - 将泛型类型声明为接口(interface)的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28186624/

相关文章:

c# - 为什么 .NET XML 将 xlmns 属性附加到我添加到文档的 XmlElements?我能阻止吗?

C# 为值排序 JSON

java - 实例化类型参数的对象

r - 使用 R 的泛型函​​数,何时以及为什么?

具有泛型类型的 Kotlin 密封接口(interface)不会推断其子类型的约束

C# 创建 "wireframe"/3D "map"

C#,创建(方法?)表达式并调用它

c# - Visual Studio 不同语言的文本搞砸了

swift - 具有子类类型的类方法调用闭包的基类

java - 如何获取具有多个泛型类型的类型来匹配类型参数?