Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我如何通过接口解决这个问题?_C#_Interface - Fatal编程技术网

C# 我如何通过接口解决这个问题?

C# 我如何通过接口解决这个问题?,c#,interface,C#,Interface,我使用的是实体框架,这就是我的问题所在,但它可能并不相关,因为我认为这是一个通用的C#问题 我有一个MyContext类,它有许多DbSet属性 为了对其进行单元测试,我编辑了MyContext,使其成为IDbSet,并对其进行了模拟IDbSet是实体框架的一部分,DbSet实现了它,因此两者几乎相同 一切都是这样工作的,因为我可以对IDbSet做我能对DbSet 除了一件事,DbSet之外的所有东西都有一个名为SqlQuery(…)的方法,我也希望能够从我的IDbSet调用该方法 由于我无法更

我使用的是实体框架,这就是我的问题所在,但它可能并不相关,因为我认为这是一个通用的C#问题

我有一个
MyContext
类,它有许多
DbSet
属性

为了对其进行单元测试,我编辑了MyContext,使其成为
IDbSet
,并对其进行了模拟
IDbSet
是实体框架的一部分,DbSet实现了它,因此两者几乎相同

一切都是这样工作的,因为我可以对
IDbSet
做我能对
DbSet

除了一件事,
DbSet
之外的所有东西都有一个名为
SqlQuery(…)
的方法,我也希望能够从我的
IDbSet
调用该方法

由于我无法更改
DbSet
IDbSet
,这给我留下了一个难题。我不知道该怎么做,所以我的
IDbSet
能够以某种逻辑方式向其添加
SearchQuery(…)
方法


这有意义吗?我很困惑,所以我可能忽略了一些非常简单的事情,比如复制和粘贴
IDbSet
,重命名它并添加
SearchQuery()
。有什么想法吗?

嗯,这可能不是最优雅的解决方案,但您可以简单地编写如下扩展方法:

public IEnumerable<T> SearchQuery(this IDbSet<T> set, string query)
{
    var dbSet = set as DbSet<T>;
    if (dbSet != null)
    {
        return dbSet.SqlQuery(query);
    }
    else 
    {
        throw new NotSupportedException();
    }
}
public IEnumerable SearchQuery(此IDbSet集,字符串查询)
{
var dbSet=设置为dbSet;
if(dbSet!=null)
{
返回dbSet.SqlQuery(query);
}
其他的
{
抛出新的NotSupportedException();
}
}
编辑

我相信我得到了你想要的东西-到处都是包装纸,可能比它的价值更麻烦,但值得一看:

// An interface which implements IDbSet<T> and adds on the method you want
public interface IExtendedDbSet<T> : IDbSet<T>
    where T : class
{
    DbSqlQuery<T> SqlQuery(string sql, object[] parameters);
}

// Implement this interface by wrapping around a regular DbSet<T>.
// You implement all the methods and properties by just wrapping the DbSet<T>
// calls
public class ExtendedDbSet<T> : IExtendedDbSet<T>
    where T : class
{
    private readonly DbSet<T> _dbSet;

    public ExtendedDbSet(DbSet<T> dbSet) { _dbSet = dbSet; }

    DbSqlQuery<T> IExtendedDbSet<T>.SqlQuery(string sql, object[] parameters)
    {
        return _dbSet.SqlQuery(sql, parameters);
    }

    T IDbSet<T>.Add(T entity) { return _dbSet.Add(entity); }
    T IDbSet<T>.Attach(T entity) { return _dbSet.Attach(entity); }
    TDerivedEntity IDbSet<T>.Create<TDerivedEntity>() { return _dbSet.Create<TDerivedEntity>(); }
    T IDbSet<T>.Create() { return _dbSet.Create(); }
    T IDbSet<T>.Find(params object[] keyValues) { return _dbSet.Find(keyValues); }
    ObservableCollection<T> IDbSet<T>.Local { get { return _dbSet.Local; } }
    T IDbSet<T>.Remove(T entity) { return _dbSet.Remove(entity); }
    IEnumerator<T> IEnumerable<T>.GetEnumerator() { return ((IEnumerable<T>)_dbSet).GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_dbSet).GetEnumerator(); }
    Type IQueryable.ElementType { get { return ((IQueryable)_dbSet).ElementType; } }
    Expression IQueryable.Expression { get { return ((IQueryable)_dbSet).Expression; } }
    IQueryProvider IQueryable.Provider { get { return ((IQueryable)_dbSet).Provider; } }
}

// A regular context class, no special interfaces to implement or
// custom properties or anything.
public class MyContext : DbContext
{
    public DbSet<Car> Cars { get; set; }
}

// An interface representing your context, which exposes extended DbSet<T>
// for your sets. Also define SaveChanges() and whatever else you may need
// to call on your context object.
public interface IMyContext
    : IDisposable
{
    IExtendedDbSet<Car> Cars { get; }
    int SaveChanges();
}

// A wrapper around your regular context. For each set, return an
// ExtendedDbSet<T> wrapper.
public class MyContextWrapper : IMyContext
{
    private readonly MyContext _myContext;

    public MyContextWrapper(MyContext myContext) { _myContext = myContext; }

    IExtendedDbSet<Car> IMyContext.Cars
    {
        get { return new ExtendedDbSet<Car>(_myContext.Cars); }
    }

    void IDisposable.Dispose()
    {
        _myContext.Dispose();
    }

    int IMyContext.SaveChanges()
    {
        return _myContext.SaveChanges();
    }
}

// Define your context variable as IMyContext, and create it
// by creating a wrapper around a regular context. The properties
// of the interface will be extended wrappers around your sets.
internal class Program
{
    private static void Main(string[] args)
    {
        using (IMyContext context = new MyContextWrapper(new MyContext()))
        {
            Console.WriteLine(context.Cars.SqlQuery("select 1", new object[0]));
        }
    }
}
//实现IDbSet并添加到所需方法上的接口
公共接口IExtendedBSet:IDbSet
T:在哪里上课
{
DbSqlQuery SqlQuery(字符串sql,对象[]参数);
}
//通过环绕常规DbSet实现此接口。
//只需包装DbSet即可实现所有方法和属性
//召唤
公共类extendedbset:iextendedbset
T:在哪里上课
{
私有只读数据库集_DbSet;
公共扩展DbSet(DbSet-DbSet){u-DbSet=DbSet;}
DbSqlQuery iextendedbset.SqlQuery(字符串sql,对象[]参数)
{
返回_dbSet.SqlQuery(sql,参数);
}
添加(T实体){return_dbSet.Add(实体);}
T IDbSet.Attach(T entity){return_dbSet.Attach(entity);}
TDerivedEntity IDbSet.Create(){return _dbSet.Create();}
T IDbSet.Create(){return_dbSet.Create();}
T IDbSet.Find(params object[]keyValues){return_dbSet.Find(keyValues);}
ObservableCollection IDbSet.Local{get{return}
删除(T实体){return_dbSet.Remove(实体);}
IEnumerator IEnumerable.GetEnumerator(){return((IEnumerable)_dbSet.GetEnumerator();}
IEnumerator IEnumerable.GetEnumerator(){return((IEnumerable)_dbSet.GetEnumerator();}
类型IQueryable.ElementType{get{return((IQueryable)u dbSet.ElementType;}
表达式{get{return((IQueryable)u dbSet.Expression;}
提供程序{get{return((IQueryable)\ u dbSet.Provider;}}
}
//一个常规的上下文类,没有要实现的特殊接口或
//自定义属性或任何东西。
公共类MyContext:DbContext
{
公共数据库集车辆{get;set;}
}
//一个表示上下文的接口,它公开了扩展的数据库集
//为了你的布景。还可以定义SaveChanges()以及您可能需要的任何其他内容
//调用上下文对象。
公共接口IMyContext
:IDisposable
{
IExtendedbset Cars{get;}
int SaveChanges();
}
//围绕常规上下文的包装器。对于每个集合,返回一个
//扩展数据库集包装器。
公共类MyContextWrapper:IMyContext
{
私有只读MyContext\u MyContext;
公共MyContextWrapper(MyContext MyContext){u MyContext=MyContext;}
iextenddbset IMyContext.Cars
{
获取{returnnewextendedbset(_myContext.Cars);}
}
void IDisposable.Dispose()无效
{
_myContext.Dispose();
}
int IMyContext.SaveChanges()
{
返回_myContext.SaveChanges();
}
}
//将上下文变量定义为IMyContext,并创建它
//通过围绕常规上下文创建包装器。属性
//该接口的一部分将围绕您的集合进行扩展包装。
内部课程计划
{
私有静态void Main(字符串[]args)
{
使用(IMyContext context=new MyContextWrapper(new MyContext()))
{
Console.WriteLine(context.Cars.SqlQuery(“选择1”,新对象[0]);
}
}
}

一个能概括你的问题的标题怎么样?你能想出一个吗?我不能:S我尝试过“当通过更改属性来使用类本身的接口来模拟类时,当我无法访问接口或类(因为它们属于外部库)时,如何保留对不属于原始接口的方法的访问权限?”但是最大长度是150个字符。这不会使所有使用SearchQuery的测试都失败吗?我可能可以使用反射或类似的方法,而不是只强制转换到
DbSet
。除非有更好的解决办法。也许我可以扩展
DbSet
并在其上添加一个接口。当我第一次开始使用EF时,没有
IDbSet
,所以我就是这么做的。也许我可以让它实现
IDbSet
,而不是存储对
DbSet的引用。在本例中,
iextendedbset
已经实现了
IDbSet
,因此它从基本接口获取所有其他属性/方法。您仍然需要一个常规的
DbSet
实例,因为实体框架提供了这个实例。您可以尝试从
DbSet
继承,而不是合成,但是您可能无法获得所有的p