1

我一直在为一个项目构建一个小型访问规则模块,其中每个特定规则都由一个通用Rule<TEntity>对象反映。该规则需要一个委托来执行特定的逻辑。

有一个RulesContext类提供方法来检查对某个实体“foo”的访问,如下所示:

rulesContext.CanIRead<Foo>(myFoo);

我的意图是将设置过程中构建的所有规则存储到一个集合中。但我尝试的每一种方法都会导致死胡同。

我想到了类似的东西:

IDictionary<Type, Rule<object>> _rules = new Dictionary<Type, Rule<object>>();

和:

var fooRule = new Rule<Foo>(foo => foo.FullfillsACertainFooCriterion())
_rules.Add(typeof(Foo), fooRule);

CanIRead实现将确保正确使用字典:

public bool CanIRead<TEntity>(TEntity entity)
{
    var rule = _rules[typeof(entity)];
    return rule.CanIRead(entity);
}

但是编译器不喜欢这样:Rule<Foo>不能分配给类型为 的参数Rule<object>。哪种是有意义的,因为它会违反合同(这表示我可以将字典的方法与任何对象一起用作参数,这对于仅接受 Foo 类型对象的 fooRule 不成立。- Liskov 原则)

但是我想不出解决这个问题的方法。如何将Rule不同类型的对象存储在一个集合中?

4

4 回答 4

2

你能做这个吗:

[TestFixture]
public class ContraVariance
{
    [Test]
    public void TestNameTest()
    {
        var rules = new List<IRule<object>>(); //object is used just for demo here, probably some interface of yours is better
        rules.Add(new Rule<A>());
        rules.Add(new Rule<B>());
    }
}
public class A { }
public class B { }

public class Rule<TEntity> : IRule<TEntity>
{

}

public interface IRule<out T>
{
}

如果不是,我认为您必须有一个非通用的 IRule 或 RuleBase(类)接口中的 out 关键字意味着 T 仅存在(协变),您可以在此处阅读。我想在你的情况下这将是一个问题,我怀疑规则有将 TEntity 作为参数传递的方法。

于 2012-10-31T14:13:02.270 回答
1

这本质上是非类型安全的。
如果你写,你想发生什么

_rules[typeof(Foor)].CanRead(new Bar());

您需要创建一个非泛型基类或接口来存储在字典中。

于 2012-10-31T14:07:03.620 回答
1

而不是使用IDictionary<Type, object>which 可以保存任何东西(例如DateTime)作为字典中的值,您可以使值严格规则对象

这里

namespace RuleConsole
{
   class Program
   {
      static void Main(string[] args)
      {
         var context = new RulesContext();

         var objA = new A();
         var objB = new B();

         context.AddRule<A>(new Rule<A>(objA));
         context.AddRule<B>(new Rule<B>(objB));

         Console.WriteLine(context.CanIRead<A>(objA));
         Console.WriteLine(context.CanIRead<B>(objB));

         Console.ReadKey();
      }
   }

   public interface IRule { }
   public interface IRule<T> : IRule { }

   public class Rule<T> : IRule<T> 
   {
      T _entity;
      public Rule(T entity)
      {
         _entity = entity;
      }
   }

   public class A { }
   public class B { }

   public class RulesContext
   {
      Dictionary<Type, IRule> _ruleDict= new Dictionary<Type, IRule>();

      public void AddRule<TEntity>(Rule<TEntity> rule)
      {
         _ruleDict.Add(typeof(TEntity), rule);
      }

      public bool CanIRead<TEntity>(TEntity entity)
      {
         var rule = (IRule<TEntity>)_ruleDict[typeof(TEntity)];

         //CanIRead implementation here

         return rule != null;
      }
   }
}
于 2012-11-09T10:36:10.880 回答
0

好吧,这几乎是令人尴尬的——但我认为你刚刚帮助我解开了我的大脑 :-)

如果问题IDictionary<Type, Rule<object>>太具体,IDictionary<Type, object>那么诀窍是:

var fooRule = new Rule<Foo>(foo => foo.FullfillsACertainFooCriterion())
_rules.Add(typeof(Foo), fooRule);

(与问题相同,但这次编译)

public bool CanIRead<TEntity>(TEntity entity)
{
    var rule = (Rule<TEntity>)_rules[typeof(entity)];
    return rule.CanIRead(entity);
}

我脑子里的障碍是,我认为其中的类型参数越通用,Rule<...>字典中应该允许的对象越多,但在这种情况下,情况恰恰相反:参数越通用,越具体合同得到。

拿:

IDictionary<Rule<Foo>>

通过替换Rule它的基类object,字典变得更加通用。但是,通过替换Foo但是,通过object,整个事情实际上变得更加专业!

这样做的全部原因是类型参数Rule被用作输入参数。

这是一个重要的教训...

于 2012-10-31T14:51:32.547 回答