Get class property depending on generic interface - c#

Lets say i have this:
public interface IMyInterface<T>
{
}
public class MyClass
{
public IMyInterface<Foo> Foos {get; set;}
public IMyInterface<Bar> Bars {get; set;}
}
I want to have a method like this one
MyClass.Interfaces<T>()
Which will return MyClass.Foos or MyClass.Bars Depending on T value.
How i do that?
It's very similar on how EF works.

It requires some plumbing and casting, but you could do that with a dictionary:
public interface IMyInterface<T> {
}
public class Foo { }
public class Bar { }
public class MyClass {
Dictionary<Type, object> myInterfaces = new Dictionary<Type, object>();
public IMyInterface<Foo> Foos {
get { return (IMyInterface<Foo>)myInterfaces[typeof(Foo)]; }
set { myInterfaces[typeof(Foo)] = value; }
}
public IMyInterface<Bar> Bars {
get { return (IMyInterface<Bar>)myInterfaces[typeof(Bar)]; }
set { myInterfaces[typeof(Bar)] = value; }
}
public IMyInterface<T> Interfaces<T>() {
return (IMyInterface<T>)myInterfaces[typeof(T)];
}
}

public class MyClass
{
public IMyInterface<Foo> Foos { get; set; }
public IMyInterface<Bar> Bars { get; set; }
public IMyInterface<T> Interfaces<T>()
{
var property = GetType().GetProperties()
.Where(x => x.PropertyType.Name.StartsWith("IMyInterface")
&&
x.PropertyType.GenericTypeArguments.Contains(typeof(T)))
.FirstOrDefault();
if (property != null)
return (IMyInterface<T>)property.GetValue(this);
return null;
}
}

Related

Multiple classes that implement a generic interface in a single array

Say I have a generic interface that stores a value that is typed by the generic parameter:
public interface IFoo<TValue>
{
TValue SomeValue { get; set; }
}
Then I have two classes, StringFoo and DoubleFoo whose SomeValues are strings and doubles respectively:
public class StringFoo : IFoo<string>
{
string SomeValue { get; set; }
}
public class DoubleFoo : IFoo<double>
{
double SomeValue { get; set; }
}
I now decide that I want an array that can contain both StringFoos and DoubleFoos:
var foos = IFoo<object>[] {
new StringFoo { SomeValue = "a value" },
new DoubleFoo { SomeValue = 123456789 }
}
I would think that, since both string and double are subclasses of object, they would both be allowed in this array. However, I thought wrong.
So, I tried using covariance:
public interface IFoo<out TValue>
But, since the interface contains both setters and getters, I can't do this.
So, can two classes that implement a generic interface in one array?
The problem can be solved in the way Bar class is implemented (bad example provided as well). The issue is that whenever one tries to use generic interface or class implementing generic interface code may compile (providing right casts) but code will throw InvalidCastException during runtime.
public interface IFoo<TValue>
{
TValue SomeValue { get; set; }
}
public class StringFoo : IFoo<string>
{
public string SomeValue { get; set; }
}
public class DoubleFoo : IFoo<double>
{
public double SomeValue { get; set; }
}
public class Foo<TValue> : IFoo<TValue>
{
public TValue SomeValue { get; set; }
}
public abstract class Bar
{
}
public class Bar<TValue> : Bar, IFoo<TValue>
{
public TValue SomeValue { get; set; }
}
public static class Verify
{
public static void QuestionArray()
{
var foos = new IFoo<object>[]
{
(IFoo<object>) new StringFoo { SomeValue = "a value" },
(IFoo<object>) new DoubleFoo { SomeValue = 123456789 }
};
}
public static void BadAnswerArray()
{
var foo = new IFoo<object>[]
{
(IFoo<object>) new Foo<string>(),
new Foo<object>(),
};
}
public static void GoodAnswer()
{
var foo = new Bar[]
{
new Bar<string>(),
new Bar<object>(),
new Bar<double>()
};
}
}
And to verify solution one can run tests where only GoodAnswerTest will pass:
public class GenericsInArrayTests
{
[Fact]
public void QuestionArrayTest()
{
Verify.QuestionArray();
}
[Fact]
public void BadAnswerTest()
{
Verify.BadAnswerArray();
}
[Fact]
public void GoodAnswerTest()
{
Verify.GoodAnswer();
}
}

Winforms DataGridView columns from datasource

I have base class and some inherited classes, like this:
public abstract class Base
{
public long ID { get; set; }
public string Name { get; set; }
public virtual string Description { get { return "Base"; } }
}
public class A : Base
{
public override string Description { get { return "A"; } }
}
public class B : Base
{
private string extraInfo;
public override string Description { get { return "B"; } }
public string ExtraInfo
{
get { return extraInfo; }
set { extraInfo = value; }
}
}
I have collection of these objects and I set this collection to DataSource of DataGridView. Then, columns of DataGridView will be created by Base class's properties (ID, Name. Description). Is there any way to reflect also concrete implementation properties?
List<Base> items = new List<Base>();
DataGridView dgv = new DataGridView();
dgv.DataSource = new BindingList<Base>(items);
In this case, I want also column for ExtraInfo property of class B.
Inherit class B too:
public class Base
{
public long ID { get; set; }
public string Name { get; set; }
public virtual string Description { get { return "Base"; } }
}
public class A : Base
{
public override string Description { get { return "A"; } }
}
public class B : Base
{
private string extraInfo;
public override string Description { get { return "B"; } }
public string ExtraInfo
{
get { return extraInfo; }
set { extraInfo = value; }
}
}

C# - Passing different type of objects through the same method

Original Question
So I have this 3 objects...
public class obj1
{
public int Id { get; set; }
public string Name { get; set; }
}
public class obj2
{
public int AccNum { get; set; }
public string Name { get; set; }
}
public class obj3
{
public string Email { get; set; }
public string Phone { get; set; }
}
... and one method that is supposed to receive one of them, after evaluating the object type the program should decide which function to call.
I've tried with generics but it doesn't work as I expected. So far this is what I've got...
public class NotificationHelper: INotificationHelper
{
public bool SendNotification<TNotInfo>(TNotInfo obj) where TNotInfo : class
{
if (contract.GetType() == typeof (obj1))
{
var sender = new SendSMS();
return sender.Send(obj);
}
if (contract.GetType() == typeof(obj2))
{
var sender = new SendPush();
return sender.Send(obj);
}
else
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
}
but I get the error "Cannot convert from TNotInfo to Models.obj1". Is there any way to overcome this issue? Or I have to change my logic?
Appreciate any help, thanks in advance.
*Edit
using System;
namespace EmailNotifications
{
public interface IEmailNotification
{
void SendEmailNotification();
}
public class EmailNotificationA : IEmailNotification
{
public void SendEmailNotification(Contract1 a)
{
Console.WriteLine($"Sending EmailNotificationA ({a})");
}
}
public class EmailNotificationB : IEmailNotification
{
public void SendEmailNotification(Contract2 b)
{
Console.WriteLine($"Sending EmailNotificationB ({b})");
}
}
public class EmailNotificationC : IEmailNotification
{
public void SendEmailNotification(Contrac3 c)
{
Console.WriteLine($"Sending EmailNotificationC ({c})");
}
}
public class EmailNotificationService
{
private readonly IEmailNotification _emailNotification;
public EmailNotificationService(IEmailNotification emailNotification)
{
this._emailNotification = emailNotification;
}
public void ServiceHelper()
{
_emailNotification.SendEmailNotification();
}
}
}
Above solution is what I was trying to achieve, applying strategy design pattern. But I couldn't manage to make my interface method receive different objects, this is required because each notification has is own implementation. As visible at the none working example above, I have 3 different implementation of the same method all of them receiving different objects. Any idea of how to make this logic work?
This is the kind of thing that interfaces were designed to do. First, define a common interface:
public interface INotifier
{
bool Notify();
}
Second, implement it in your objX classes:
public class obj1 : INotifier
{
public int Id { get; set; }
public string Name { get; set; }
public bool Notify()
{
var sender = new SendSMS();
return sender.Send(this);
}
}
public class obj2 : INotifier
{
public int AccNum { get; set; }
public string Name { get; set; }
public bool Notify()
{
var sender = new SendPush();
return sender.Send(this);
}
}
public class obj3 : INotifier
{
public string Email { get; set; }
public string Phone { get; set; }
public bool Notify()
{
var sender = new SendEmail();
return sender.Send(this);
}
}
And finally, change your notification method to accept the interface type as the parameter:
public class NotificationHelper : INotificationHelper
{
public bool SendNotification(INotifier obj)
{
return obj.Notify();
}
}
Edit (2019):
I'm revisiting this answer as it seems to be getting a fair amount of visibility. OP has probably long since moved on, but for others that may stumble upon this answer, here's another solution.
I still believe that interfaces are the way to go. However, the interface suggested above is extremely generic and ultimately not terribly useful. It also runs into some DRY violations because, as Fabio said in a comment, if two objX classes implement notifications in the same way, this approach forces you to duplicate the code between them.
Instead of one global interface, instead have interfaces for each specific notification task, i.e. ISMSNotification, IPushNotification, IEmailNotification. You can then use the mixin pattern to give each interface instance a default implementation of the send method:
interface ISmsNotifier
{
int SmsId { get; }
string SmsName { get; }
}
static class ISmsNotifierExtensions
{
public static bool NotifySms(this ISmsNotifier obj)
{
var sender = new SendSMS();
return sender.Send(obj);
}
}
// ---------------------------------------------
interface IPushNotifier
{
int PushAccNum { get; }
string PushName { get; }
}
static class IPushNotifierExtensions
{
public static bool NotifyPush(this IPushNotifier obj)
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
// ---------------------------------------------
interface IEmailNotifier
{
string EmailAddress { get; }
string EmailPhone { get; }
}
static class IEmailNotifierExtensions
{
public static bool NotifyEmail(this IEmailNotifier obj)
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
You can then implement it in the objX classes like so:
public class obj1 : INotifier, ISmsNotifier
{
public int SmsId { get; set; }
public string SmsName { get; set; }
public bool Notify() => this.NotifySms();
}
public class obj2 : INotifier, IPushNotifier
{
public int PushAccNum { get; set; }
public string PushName { get; set; }
public bool Notify() => this.NotifyPush();
}
public class obj3 : INotifier, IEmailNotifier
{
public string EmailAddress { get; set; }
public string EmailPhone { get; set; }
public bool Notify() => this.NotifyEmail();
}
Notice that using this approach it's easy to not only support objects which use identical notification systems, you can also support objects with multiple notification systems:
public class obj4 : INotifier, IEmailNotifier, IPushNotifier
{
public int PushAccNum { get; set; }
public string PushName { get; set; }
public string EmailAddress { get; set; }
public string EmailPhone { get; set; }
public bool Notify() => this.NotifyEmail() && this.NotifyPush();
}
You might notice that this approach makes NotificationHelper obsolete since it's no longer necessary to pass the objects through a processing step to determine which notification system to process the object through. That is true, and maybe rightfully so, since the objects should be fully capable of deciding that for themselves (depending on your mentality approaching this problem). However, NotificationHelper may still have its uses, such as if you wanted to preprocess the information that's getting sent to the notification services, or if you wanted a common point of entry to help with mocking and testing.
C# 8 Note:
A proposed feature of C# 8 is the ability to give interfaces a default implementation of methods within the interface definition itself. When (if) that happens, you don't need to use the mixin pattern anymore and can directly define the default method implementations in the interfaces. The feature hasn't yet been finalized, but it might look something like this:
interface ISmsNotifier
{
int SmsId { get; }
string SmsName { get; }
public bool NotifySms()
{
var sender = new SendSMS();
return sender.Send(this);
}
}
// ---------------------------------------------
interface IPushNotifier
{
int PushAccNum { get; }
string PushName { get; }
public bool NotifyPush()
{
var sender = new SendEmail();
return sender.Send(this);
}
}
// ---------------------------------------------
interface IEmailNotifier
{
string EmailAddress { get; }
string EmailPhone { get; }
public bool NotifyEmail()
{
var sender = new SendEmail();
return sender.Send(this);
}
}
Another approach will be overload methods.
Because you have different logic based on the given type. And types have nothing in common (interface/abstract class).
public class NotificationHelper
{
public bool SendNotification(obj1 obj)
{
var sender = new SendSMS();
return sender.Send(obj);
}
public bool SendNotification(obj2 obj)
{
var sender = new SendPush();
return sender.Send(obj);
}
public bool SendNotification(obj3 obj)
{
var sender = new SendEmail();
return sender.Send(obj);
}
}
Then using will be clear enough
var someObject = GetObjectFromSomeWhere();
var isSuccessful = SendNotification(someObject);
I would suggest creating a parent class from which these 3 inherit
public class ParentType { }
public class Obj1 : ParentType { ... }
The method would then just request the parent type, such as:
public bool SendNotification(ParentType obj) { ... }

Expendable complex types inside complex types in any collection (Property grid)

Hello I want to have a expandable collection of complex types which are inside of other complex type.
How I want to do this:
private static void SetExpandableAttrForType(Type type)
{
var props = type.GetProperties();
foreach (var prop in props.Where(x =>!x.PropertyType.IsSimpleType()&& x.CanWrite))
{
SetExpandableAttrForType(prop.PropertyType);
}
TypeDescriptor.AddAttributes(type, new TypeConverterAttribute(typeof (ExpandableObjectConverter)));
}
and then
SetExpandableAttrForType(arrayInstance.GetType().GetElementType());
Test model:
public class Class1
{
public Class2 Class2Inclass1 { get; set; }
public Class2[] Class2Array { get; set; }
}
public class Class2
{
public Class3 Class3Inclass2 { get; set; }
public string Class2String { get; set; }
public string Class2String2 { get; set; }
}
public class Class3
{
public Class4 Class4Inclass3 { get; set; }
public string Class3String { get; set; }
public int Class3Int { get; set; }
}
public class Class4
{
public int Class4Int { get; set; }
public DateTime Class4Datetime { get; set; }
}
It works fine for types but not for collection of types.
The great thing about programming is this, when u tell somebody about the problem, often you start to look at it from another angle. The problem was that I need instance of this nested complex type. CellValueChanged event give me type and then I just need to create instance of it.
private void propertyGridControl1_CellValueChanged(object sender, CellValueChangedEventArgs e)
{
var changedObject = e.Value;
if (changedObject != null)
{
if (changedObject.GetType().IsArray || changedObject.GetType().IsGenericList())
{
var collectionItems = changedObject as IEnumerable;
if (collectionItems != null)
foreach (var item in collectionItems)
{
SetValueOfCollectionComplexObject(item);
}
}
}
}
public void SetValueOfCollectionComplexObject(object item)
{
var complexProps = item.GetType().GetProperties().Where(x => !x.PropertyType.IsSimpleType());
foreach (var prop in complexProps)
{
if (prop.GetValue(item) == null)
{
prop.SetValue(item, Activator.CreateInstance(prop.PropertyType));
SetValueOfCollectionComplexObject(prop.GetValue(item));
}
}
}

Reduce code duplicates

Currently I have quite many classes (5) that have just 2 properties but have different names for different purposes:
public class Class1
{
public Class1()
{
}
public string Id { get; set; }
public string Value { get; set; }
}
public class Class2
{
public Class2()
{
}
public string Id { get; set; }
public string Value { get; set; }
}
........
public class Class5
{
public Class5()
{
}
public string Id { get; set; }
public string Value { get; set; }
}
Then I have for each of those classes a method that will return a List<Class>.
public static List<Class1> GetClass1()
{
Dictionary<string, string> s = GetSomeResults1();
List<Class1> _s = new List<Class1>();
foreach (var item in s)
{
Class1 c = new Class1();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
public static List<Class2> GetClass2()
{
Dictionary<string, string> s = GetSomeResults2();
List<Class2> _s = new List<Class2>();
foreach (var item in s)
{
Class2 c = new Class2();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
......
public static List<Class5> GetClass5()
{
Dictionary<string, string> s = GetSomeResults5();
List<Class5> _s = new List<Class5>();
foreach (var item in s)
{
Class5 c = new Class5();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
Any advise how can I better make this code?
Use a base class to put the shared properties and functions in:
public class BaseClass
{
public string Id { get; set; }
public string Value { get; set; }
// shared properties and methods
}
public class Class1 : BaseClass
{
// own properties and methods
}
public class Class2 : BaseClass
{
// own properties and methods
}
I will suggest create a seperate class for
public string Id { get; set; }
public string Value { get; set; }
and call inside class.
You can use class inheritance and put common parts of code to a base class like this:
/// <summary>
/// Base class
/// </summary>
public class BaseClass
{
public BaseClass()
{
}
public string Id { get; set; }
public string Value { get; set; }
public virtual List<BaseClass> GetClass();
protected List<TClass> GetList<TClass> (Dictionary<string, string> s) where TClass : BaseClass, new() {
List<TClass> _s = new List<TClass>();
foreach (var item in s)
{
TClass c = new TClass();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
}
public class Class1 : BaseClass
{
public override List<Class1> GetClass() {
Dictionary<string, string> s = GetSomeResults1();
return GetList<Class1>(s);
}
}
You can use a base class:
public abstract class BaseClass{
public string Id { get; set; }
public string Value { get; set; }
}
public class Class1 : BaseClass
{
public Class1()
{
}
}
public class Class2: BaseClass
{
public Class2()
{
}
}
Now you can make a generic method which returns the interface of List<T> where T is of type BaseClass
public static List<T> GetClass<T>(Func<Dictionary<string, string> func) where T : BaseClass, new()
{
Dictionary<string, string> s = func();
List<T> _s = new List<T>();
foreach (var item in s)
{
T c = new T();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
Then call:
List<Class2> class2list = GetClass<Class2>(GetSomeResults2);
Patrick Hofman's answer is right, but i'd also add that using a BaseClass would allow you to reduce the amount of code working with your classes.
public static List<T> GetClassList() where T:BaseClass
{
Dictionary<string, string> s = GetSomeResults<T>();
List<T> _s = new List<T>();
foreach (var item in s)
{
T c = new T();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
Changing just this function is not enough though, you also need a way to implement the GetSomeResults() methods. I don't really know what your logic looks like and how different these methods are, but smth like this can help in the worst case when methods are completely different.
public static Dictionary<string, string> GetSomeResults<T>() where T : BaseClass
{
if (T == typeof(Class1))
{
return GetSomeResults1();
}
else if (T == typeof(Class2))
{
//You got it..
}
}

Categories