2015-01-28 4 views
1

Я шаблонного типа, который используется, чтобы дать некоторые мета-данные об объекте упорствовать:Объявить общий тип как свойство интерфейса?

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, вот пример того, какой вопрос я столкнулся, если я имею общий интерфейс:

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#, чтобы объявить интерфейс с общее свойство типа реализации?

+0

и что это вопрос? –

+1

Непонятно, почему у вас не может быть IPersistedObject 'вы можете немного объяснить? и какова конечная цель? чего вы пытаетесь достичь? Это похоже на проблему XY. –

+0

Какую проблему вы пытаетесь решить здесь?Я не совсем понимаю вашу иерархию типов, поэтому я не очень помогаю, но так же, как некоторые советы: используйте систему типов только в той мере, в которой это помогает вам легко рассуждать о вашем коде и его гарантиях времени компиляции. Если в вашей иерархии типов вы делаете умственную гимнастику только для того, чтобы реализовать интерфейс (я уже был в этом месте раньше), вам, вероятно, будет лучше с меньшим временем безопасности компиляции и немного больше волос на голове. –

ответ

3

Вы можете использовать любопытно повторяющийся шаблон шаблона, чтобы заблокировать это немного дальше. Это не пуленепробиваемый, но предполагая, что вы не мазохист, и вы не возражаете против того, что теоретически возможно создать бессмысленные реализации интерфейса, которые нарушают инварианты, которые вы пытаетесь гарантировать, вы можете сделать это:

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>, и в конечном итоге разорвать контракт вы пытаетесь сколотить, что в простых словах заключается в следующем:

Сохраняемый объект должен иметь определение gettable, которое является определением сохраняемого элемента его собственной модели e

Система типа C# просто не оборудована, чтобы справиться с этим элегантно. Мой совет - рано уйти, перейдите на object или dynamic, где это возможно, и научитесь жить с потерей определенных гарантий времени компиляции.

Предполагая, что вы готовы пожертвовать компиляции безопасности времени, вы могли бы сделать что-то вроде этого:

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; } } 
} 
+0

Посмотрите последнюю часть моего вопроса, если у меня есть IPersistedObject 'У меня будет проблема в указанный момент. – J4N

+0

@ J4N См. Мое обновление. –

+0

Это «динамическое» кажется потрясающим, позвольте мне попробовать в своем прототипе, чтобы увидеть, заблокирован ли я чем-то. – J4N